由于语早死,题目&样例看了很久很久才看懂QAQ……
其实就是把单词建一个AC自动机,用val[i]表示i节点的前缀出现次数,则每个叶子节点的val即为所求。插入字符串时,一路上val++,再利用fail的性质,从下向上累加val(为了保证后搜索的fail指针先累加,可以保存bfs序)。
代码:
#include <cstdio>
#include <map>
#include <string>
#include <iostream>
#include <cstring>
#include <queue>
#define maxn 1000000+10
using namespace std;
int n,sz=1,q[maxn],tail,head,ch[maxn][27],val[maxn],fail[maxn];
char s[205][maxn];
int m[205];
int insert(int j)//一开始传递的参数是字符串,T了(毕竟是10^6),调了好久才发现QAQ
{
scanf("%s",s[j]);
int u=0,n=strlen(s[j]);
for (int i=0;i<n;i++)
{
int c=s[j][i]-'a';
if (!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
ch[u][c]=sz;
val[sz++]=1;
}
else val[ch[u][c]]++;
u=ch[u][c];
}
return u;
}
void get_fail()
{
head=tail=0;
for (int i=0;i<26;i++)
if (ch[0][i]) q[++tail]=ch[0][i];
while (head<tail)
{
int u=q[++head];
for (int i=0;i<26;i++)
if (ch[u][i])
{
int j;
for ( j=fail[u];j&&!ch[j][i];j=fail[j]);
fail[ch[u][i]]=ch[j][i];
q[++tail]=ch[u][i];
}else ch[u][i]=ch[fail[u]][i];
}
}
int main()
{
freopen("data.out","r",stdin);
freopen("wa.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
//scanf("%s",s[i]);
m[i]=insert(i);
}
get_fail();
for (int i=tail;i;i--) val[fail[q[i]]]+=val[q[i]];
for (int i=1;i<=n;i++)printf("%d\n",val[m[i]]);
}