AC自动机.
统计每个字符串在自己和其他字符串中出现的次数。
ac自动机的概念,首先有个trie树保存了所有的字符串。
fail指针指向该字符串的后缀在整个trie树中可以做最长的前缀的位置。
每个字符串都可以由fail指针转移到是该字符串字串的位置。
所以很多统计就可以进行辣。
字符串的题好难。。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 1000000 + 10; struct AC { int a[maxn][26],sum[maxn],q[maxn],fail[maxn]; int cnt,l,r,p; char s[maxn]; void insert(int &p) { scanf("%s",s); int len=strlen(s); p=1; for(int i=0;i<len;i++) { int c=s[i]-'a'; if(!a[p][c]) a[p][c]=++cnt; p=a[p][c]; sum[p]++; } } void get_fail() { l=r=0; fail[1]=0; q[r++]=1; while(l<r) { p=q[l++]; for(int i=0;i<26;i++) if(a[p][i]) { int k=fail[p]; while(!a[k][i]) k=fail[k]; fail[a[p][i]]=a[k][i]; q[r++]=a[p][i]; } } for(int i=r-1;i>=0;i--) sum[fail[q[i]]]+=sum[q[i]]; } AC() { cnt=1; for(int i=0;i<26;i++) a[0][i]=1; } }am; int pos[maxn]; int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) am.insert(pos[i]); am.get_fail(); for(int i=1;i<=n;i++) printf("%d ",am.sum[pos[i]]); return 0; }