LG P3966 [TJOI2013]单词
Description
小张最近在忙毕设,所以一直在读论文。一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次。
Solution
对这些单词建出AC自动机,可能会有重复的单词,记录每一个单词第一次出现是第几个
在AC自动机上匹配时,匹配串经过的所有点打标记,每个点对其fail指向的点做贡献,跑一边DFS求子树和
#include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<queue> using namespace std; int n,tot=1,mp[205],len,len2,siz[1000005],pos[205]; char s[1000005],t[1000205]; struct ACAM{ int ch[26],fa,tag; }tr[1000005]; vector<int>ve[1000005]; queue<int>q; inline int read(){ int f=1,w=0; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return f*w; } void insert(char *s,int id){ int u=1; for(int i=1;i<=len;i++){ if(!tr[u].ch[s[i]-'a'])tr[u].ch[s[i]-'a']=++tot; u=tr[u].ch[s[i]-'a']; } if(!tr[u].tag)mp[id]=tr[u].tag=id,pos[id]=u; else mp[id]=tr[u].tag; } void BFS(){ for(int i=0;i<26;i++)tr[0].ch[i]=1; q.push(1); while(q.size()){ int u=q.front(); q.pop(); for(int i=0;i<26;i++){ int v=tr[u].ch[i],f=tr[u].fa; if(!v){tr[u].ch[i]=tr[f].ch[i];continue;} tr[v].fa=tr[f].ch[i],q.push(v); } } } void ask(char *s){ int u=1; for(int i=1;i<=len2;i++){ if(t[i]=='$'){u=1;continue;} u=tr[u].ch[t[i]-'a'],++siz[u]; } } void dfs(int k){ for(int i=0;i<ve[k].size();i++){ int v=ve[k][i]; dfs(v),siz[k]+=siz[v]; } } int main(){ n=read(); for(int i=1;i<=n;i++){ scanf("%s",s+1),len=strlen(s+1),insert(s,i); for(int i=1;i<=len;i++)t[++len2]=s[i]; t[++len2]='$'; } BFS(); for(int i=2;i<=tot;i++)ve[tr[i].fa].push_back(i); ask(t+1),dfs(1); for(int i=1;i<=n;i++)printf("%d\n",siz[pos[mp[i]]]); return 0; }