題目來源:http://acm.hdu.edu.cn/showproblem.php?pid=2222
這題是比較裸的AC自動機,很容易想出AC做法但卻並不容易AC。。。
1、首先!這題有重複的單詞!!
2、千萬不要在for循環裏用strlen!!這題匹配串長度1000000,如果每次循環都要strlen,那計算開銷是相當大的。我不在裏面打strlen時間343ms,如果在裏面大strlen則直接TLE。
3、最好不要用memset
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
const int N=500003;
int T,n,ans=0;
int ch[N][26],fail[N],danger[N],cnt=1;//id[N]
bool vis[N];
queue<int> q;
char s[1000009];
void ins (char *s,int x) {
int n=strlen(s),p=1,c;
for (int i=0;i<n;i++) {
c=s[i]-'a';
if (!ch[p][c]) ch[p][c]=++cnt;
p=ch[p][c];
}
danger[p]++;
}
void getfail () {
while (!q.empty()) q.pop();
int p=1,k;fail[1]=0;
q.push(1);
while (!q.empty()) {
p=q.front(); q.pop();
for (int i=0;i<26;i++) {
if (!ch[p][i]) continue;
k=fail[p];
while (!ch[k][i]) k=fail[k];
fail[ch[p][i]]=ch[k][i];
q.push(ch[p][i]);
}
}
}
void get (int p) {
for (int i=p;i;i=fail[i])
if (!vis[i]) {
vis[i]=1; q.push(i);
if (danger[i]) ans+=danger[i];
}
else break;//這裏不要接着向下搜
}
void solve () {
scanf("%s",s);
int p=1,c,len=strlen(s);//就是這裏strlen一定要在for外面計算
while (!q.empty()) q.pop();
for (int i=0;i<len;i++) {
c=s[i]-'a';
while (!ch[p][c]) p=fail[p];
p=ch[p][c];
get(p);
}
while (!q.empty()) {
vis[q.front()]=0;
q.pop();
}
}
int main () {
char s[100];
scanf("%d",&T);
while (T--) {
ans=0;cnt=1;
//memset(ch,0,sizeof(ch));
//memset(fail,0,sizeof(fail));
//memset(danger,0,sizeof(danger));
//memset(id,0,sizeof(id));
for (int i=0;i<26;i++) ch[0][i]=1;
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%s",s);
ins(s,i);
}
getfail();
solve();
printf("%d\n",ans);
for (int i=0;i<=cnt;i++) {
for (int j=0;j<26;j++) ch[i][j]=0;
fail[i]=0;
danger[i]=0;
}
}
}