http://acm.hdu.edu.cn/showproblem.php?pid=2896
对于hdu oj...发现如果数组越界,还有数组下标为负数 ,可能返回的Judge结果都是WA而不是RE。。。这道题WA了几次,因为
inline int idx(char c) {
//return c-'a'; //这里一定小心,如果没有给定字符范围的话,直接return c;
//因为可能出现负的...病毒侵袭那题就是
return c;
}
通过这题学到的:
1、通过cnt数组在O(n)时间内显示所有单词编号由小到大--如果用map存储单词的话,当然也可以按输入顺序存储顺序输出;
2、AC自动机注意首先看字符范围,定下SIGMA_SIZE以及idx函数写法
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int SIZE = 10000+10;
const int SIGMA_SIZE = 128;
const int MAXNODE = 61000;
//const int MAXS = 150 + 10;
int maxv;
struct AC
{
int f[MAXNODE];
int ch[MAXNODE][SIGMA_SIZE];
int val[MAXNODE];
int last [MAXNODE];
int cnt[MAXNODE];
int sz;
void init()
{
sz=1;
memset(ch[0],0,sizeof(ch[0]));
memset(cnt,0,sizeof(cnt));
val[0]=f[0]=last[0]=0;
}
void clear()
{
memset(cnt,0,sizeof(cnt));
}
inline int idx(char c) {
//return c-'a'; //这里一定小心,如果没有给定字符范围的话,直接return c;
//因为可能出现负的...病毒侵袭那题就是
return c;
}
void insert(char *s, int v)
{
int u=0,n=strlen(s);
for(int i=0;i<n;i++)
{
int c=idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=v;
}
void getfail()
{
queue<int>q;
f[0]=0;
for(int c=0;c<SIGMA_SIZE;c++)
{
int u=ch[0][c];
if(u)
{
f[u]=0;
q.push(u);
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<SIGMA_SIZE;c++)
{
int u=ch[r][c];
if(!u)continue;
q.push(u);
int v=f[r];
while(v && !ch[v][c])v=f[v];
f[u]=ch[v][c];
last[u]=val[f[u]]?f[u]:last[f[u]];
}
}
}
void print(int j)
{
if(j)
{
maxv=max(val[j],maxv);
cnt[val[j]]++;
print(last[j]);
}
}
void find(char *T)
{
int n=strlen(T);
int j=0;
for(int i=0;i<n;i++)
{
int c=idx(T[i]);
while(j && !ch[j][c])j=f[j];
j=ch[j][c];
if(val[j])
print(j);
else
if(last[j])print(last[j]);
}
}
};
AC ac;
int main()
{
//freopen("hdu2896.txt","r",stdin);
int n,m;
char str[SIZE];
while(scanf("%d",&n) !=EOF)
{
ac.init();
for(int i=1;i<=n;i++)
{
scanf("%s",str);
ac.insert(str,i);
}
ac.getfail();
scanf("%d",&m);
int wcnt=0,flag=0;
for(int i=1;i<=m;i++)
{
maxv=0;
flag=0;
ac.clear();
scanf("%s",str);
ac.find(str);
for(int j=1;j<=maxv;j++)
{
if(ac.cnt[j])
{
flag++;
if(flag==1)printf("web %d: ",i);
if(j<maxv)printf("%d ",j);
else printf("%d\n",j);
}
}
if(flag)wcnt++;
}
printf("total: %d\n",wcnt);
}
return 0;
}