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[N][26],d[N][26],num[N],fail[N],q[N]; char s[32]; ll ans,f[32][N]; 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; }