先貼一個大白書的代碼
來自這篇blog
//HDU2222
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=500500;
struct ACautomachine
{
int chd[N][26];//孩子節點編號
int cnt[N];//當前結點 表示字符串個數
int fail[N];//失配指針
int last[N],sz,ans;//題目需要
void init()
{
sz=1,ans=0;
memset(cnt,0,sizeof(cnt));
memset(fail,0,sizeof(fail));
memset(chd[0],0,sizeof(chd[0]));
}
void insert(char* p)//構建trie
{
int cur=0;
for(;*p;p++)
{
if(!chd[cur][*p-'a'])
{
memset(chd[sz],0,sizeof(chd[sz]));
chd[cur][*p-'a']=sz++;
}
cur=chd[cur][*p-'a'];
}
cnt[cur]++;
}
bool query(char* p)//題目需要
{
int cur=0;
for(;*p;p++)
{
if(!chd[cur][*p-'a']) break;
cur=chd[cur][*p-'a'];
}
return cnt[cur]&&(!(*p));
}
int getFail()
{
queue<int> q;
fail[0]=0;
for(int c=0;c<26;c++)
{
int u=chd[0][c];
if(u)
{
fail[u]=0/*Null*/;
q.push(u);
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();
q.pop();
for(int c=0;c<26;c++)
{
int u=chd[r][c];
if(!u)
{
//直接指向 fail
//也就是 把 trie樹 的 chd[fail[r]][c]及其子孫 全部 “複製” 作r點的子孫
chd[r][c]=chd[fail[r]][c];
continue;
}
q.push(u);
int v=fail[r];
while(v&&!chd[v][c]) v=fail[v];
//1. 令指針爲 fail[fa[u]]
//2. 若指針的一級兒子中存在一點(代表字符)與 u 相同
// 則令fail[u] 指向 當前指針的該兒子
//3. 否則 指針指向 fail[指針] 並重復 2 操作、
//目的:使得當前點及其到根的路徑(即一個字典串) 與 fail 和fail[fail]... 所代表字典串 後綴相同
// 從而實現重新匹配
fail[u]=chd[v][c];
last[u]=cnt[fail[u]] ? fail[u] : last[fail[u]];
}
}
}
void solve(int j) //題目需要
{
if(!j) return;
if(cnt[j])
{
ans+=cnt[j];
cnt[j]=0;
}
solve(last[j]);
}
void find(char* T) //題目需要
{
int n=strlen(T),j=0;
getFail();
for(int i=0;i<n;i++)
{
j=chd[j][T[i]-'a'];
if(cnt[j]) solve(j);
else if(last[j]) solve(last[j]);
}
}
}ac;
int main()
{
int t,n;
char dic[100],str[1100000];
scanf("%d",&t);
while(t--)
{
ac.init();
scanf("%d",&n);
while(n--)
{
scanf("%s",dic);
ac.insert(dic);
}
scanf("%s",str);
ac.find(str);
printf("%d\n",ac.ans);
}
return 0;
}
自己的
剛開始一點也不注意常數
TLE了好久啊[淚]
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fo(i,x,y) for (int i=(x);i<=(y);++i)
#define fd(i,x,y) for (int i=(x);i>=(y);--i)
#define oo 2139062143
using namespace std;
typedef long long ll;
typedef double db;
const int N=501000,C=27;
int T,n;
int ans;
char dic[55],str[1100000];
struct AcAutoMation{
int d[N];
int chd[N][C];
int ot[N];
int fail[N],next[N],last[N];
int bz[N];
int sz;
void del(int x)
{
next[last[x]]=next[x],last[next[x]]=last[x];
bz[x]=1;
}
void init()
{
memset(bz,0,sizeof bz);
memset(chd[0],0,sizeof chd[0]);
memset(ot,0,sizeof ot);
memset(fail,0,sizeof fail);
sz=0;
}
void insert(char *p)
{
int tmp=0;
int len=strlen(p+1);
fo(i,1,len)
{
int now=p[i]-'a';
if(!chd[tmp][now])
{
chd[tmp][now]=++sz;
memset(chd[sz],0,sizeof(chd[sz]));
}
tmp=chd[tmp][now];
}
++ot[tmp];
}
void Getfail()
{
int tmp=0;
int hd=0,tl=0;
fo(i,0,25)
{
if(chd[0][i])
{
d[++tl]=chd[0][i];
fail[chd[0][i]]=0;
}
}
while(hd++<tl)
{
tmp=d[hd];
fo(i,0,25)
if(chd[tmp][i])
{
d[++tl]=chd[tmp][i];
int to=fail[tmp];
while(to!=0&&!chd[to][i]) to=fail[to];
fail[chd[tmp][i]]=chd[to][i];
next[chd[tmp][i]]=(ot[chd[tmp][i]])?(fail[chd[tmp][i]]):(next[fail[chd[tmp][i]]]);
}
}
}
void solve(char *p)
{
int tmp=0;
int len=strlen(p+1);
fo(i,1,len)
{
int now=p[i]-'a',to=tmp;
while(!chd[to][now]&&to) to=fail[to];
tmp=chd[to][now];
for (int pp=tmp;pp;pp=next[pp])
{
if(ot[pp])
{
ans+=ot[pp],ot[pp]=0;
}
}
}
}
}ac;
int main()
{
int TT=clock();
scanf("%d\n",&T);
while(T--)
{
ac.init();
scanf("%d\n",&n);
fo(i,1,n)
{
scanf("%s\n",dic+1);
ac.insert(dic);
}
ac.Getfail();
ans=0;
scanf("%s\n",str+1);
ac.solve(str);
printf("%d\n",ans);
}
return 0;
}