您的位置:首页 > 其它

串 2016Vijos省选集训 day3[AC自动机]

2017-02-14 15:57 267 查看
1、串(string.c/.cpp/.pas)

限时1s,内存限制256MB,20个测试点

【题目描述】

兔子们在玩字符串的游戏。首先,它们拿出了一个字符串集合S,然后它们定义一个字符串为“好”的,当且仅当它可以被分成非空的两段,其中每一段都是字符串集合S中某个字符串的前缀。

比如对于字符串集合{"abc", "bca"},字符串"abb","abab"是“好”的("abb" = "ab"+"b", abab = "ab" + "ab"),而字符串“bc”不是“好”的。

兔子们想知道,一共有多少不同的“好”的字符串。

【输入格式】

第一行一个整数n,表示字符串集合中字符串的个数

接下来每行一个字符串

【输出格式】

一个整数,表示有多少不同的“好”的字符串

【样例输入】

2

ab

ac

【样例输出】

9

【数据规模】

对于20%的数据,1 <= n <= 200

对于50%的数据,1 <= n <= 2000

对于100%的数据,1 <= n <= 10000,每个字符串非空且长度不超过30,均为小写字母组成。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#define FRE(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
#define FC fclose(stdin);fclose(stdout);

typedef long long ll;
const int N=3e5+5;

int n,L,len,cnt,tr
[26],d
[26],num
,fail
,q
;
char s[32];
ll ans,f[32]
;
void insert(){
int now=1;
for(int i=0;i<len;i++){
int t=s[i]-'a';
if(!tr[now][t]) tr[now][t]=++cnt,num[cnt]=num[now]+1;
now=tr[now][t];
}
}
void AC_mach(){
int h=0,t=1;int p;
q[1]=1;fail[1]=0;
while(h!=t){
int now=q[++h];
for(int i=0;i<26;i++){
if(tr[now][i]){
p=fail[now];
while(!tr[p][i]) p=fail[p];
fail[tr[now][i]]=tr[p][i];
q[++t]=tr[now][i];
}
else{
p=fail[now];
while(!tr[p][i]) p=fail[p];
tr[now][i]=tr[p][i];
d[now][i]=1;
}
}
}
}
void first(){
cnt=1;ans=0;
for(int i=0;i<26;i++) tr[0][i]=1;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
len=strlen(s);
L=max(L,len);
insert();
}
}
void solve(){
AC_mach();
for(int i=2;i<=cnt;i++){
if(fail[i]!=1) ans++;
for(int j=0;j<26;j++){
if(tr[i][j]!=1&&d[i][j]){
f[1][tr[i][j]]++;
}
}
}
for(int i=1;i<=L;i++){
for(int j=2;j<=cnt;j++){
if(f[i][j]){
ans+=f[i][j];
for(int k=0;k<26;k++){
if(num[tr[j][k]]>=i+1){
f[i+1][tr[j][k]]+=f[i][j];
}
}
}
}
}
printf(LL,ans);
}
int main(){
FRE(string)
first();
solve();
FC
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: