您的位置:首页 > 其它

【BZOJ3172】 [Tjoi2013]单词

2016-07-12 10:09 375 查看
【题意】

   某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

【分析】

   个人觉得是用了反fail树的思想,Ans[i]=t[i].cnt+∑Ans[反fail]...不过因为有些节点的反fail会有很多个,存起来不方便。但是AC自动机的fail却只有一个,而且我们在建立AC自动机的时候是用类似宽搜的方法建的,所以保存在队列里的节点肯定是由深到浅。然后我们就可以从后往前for一遍,把i的cnt加入到i的fail的cnt里,最后每个单词最末节点的cnt就是答案。

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>

const int Maxn=(int)1e4;
const int Maxl=200;

struct node
{
int son[27],fail,cnt,ans;
}t[16035707];

int n,m,cnt=0;
int q[Maxn*Maxl+10],bj[Maxn];
char s[Maxl];

void floy()
{
int i;
for(i=1;i<=Maxn;i++) t[i].fail=0,t[i].ans=0;
}

void read()
{
memset(bj,0,sizeof(bj));
int i,j,x,ind;
scanf("%d",&n);
getchar();
for(i=1;i<=n;i++)
{
scanf("%s",s+1);
m=strlen(s+1);
x=0;
for(j=1;j<=m;j++)
{
ind=s[j]-'a'+1;
if(!t[x].son[ind]) t[x].son[ind]=++cnt;
x=t[x].son[ind];
t[x].cnt++;
if(j==m) bj[i]=cnt;
}
}
}

void Build_AC()
{
int i,x,y,j;
q[0]=0;
q[++q[0]]=0;
//for(i=1;i<=26;i++)  if(t[0].son[i]) q[++q[0]]=t[0].son[i];
for(i=1;i<=q[0];i++)
{
x=q[i];
y=t[x].fail;
for(j=1;j<=26;j++)
if(t[x].son[j])
{
//t[t[x].son[j]].fail=t[y].son[j];
t[t[x].son[j]].fail=x?t[y].son[j]:x;
q[++q[0]]=t[x].son[j];
}
else t[x].son[j]=t[y].son[j];
}
for(i=q[0];i>=1;i--)
{
t[t[q[i]].fail].cnt+=t[q[i]].cnt;
}
}

int main()
{
read();
Build_AC();
for(int i=1;i<=n;i++) printf("%d\n",t[bj[i]].cnt);
}


[BZOJ3172]

2016-07-12 10:12:39
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: