2013 成都赛区 G题
有点难度阿..
题目看错调了两天
通过这题 我了解了何为在线ac自动机
做过的 ac自动机题都是先给好模板串 再给目标串
这样getfail就是遍历一遍节点 就行
于是想到那就每次询问之前都getfail一次吧!
结果TLE..
于是只能看题解..
额..什么叫在线ac自动机?
好吧..在线ac自动机也是每询问一次就getfail一次
那怎么省时间呢?
getfail的时间复杂度就是节点数 那么就减少getfail的节点----开两棵树
一棵小树做缓存buf 每次都对她getfail 大树做堆heap
当小树的size(诶嘿)达到一个数值后就放进 大树就吃了小树(append(), - -)并getfail
询问时同时问大树和小树 求和
#include <stdio.h>
#include <string.h>
#define ff(i,n) for(int i=0;i<n;i++)
const int CH = 2,NODE = 100005;
int idx(char x)
{
return x-'0';
}
int queue[NODE];
struct DFA
{
int ch[NODE][CH],f[NODE],val[NODE],last[NODE],sz;
void init()
{
sz=1;
memset(ch[0],0,sizeof(ch[0]));
}
void nn(int u,int c)
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
void ins(char *s)
{
int u=0;
for(;*s;s++)
{
int c=idx(*s);
if(!ch[u][c])
nn(u,c);
u=ch[u][c];
}
val[u]=1;
}
void getfail()
{
int *rear=queue,*front=queue;
ff(c,CH)
{
int u=ch[0][c];
if(u)
f[u]=0,last[u]=0,*rear++=u;
}
while(rear!=front)
{
int cur = *front++;
ff(c,CH)
{
int u=ch[cur][c];
int fail=f[cur];
if(u)
{
while(fail && !ch[fail][c]) fail = f[fail];
f[u]=ch[fail][c];
last[u]=val[f[u]]?f[u]:last[f[u]];
*rear++=u;
}
}
}
}
int calc(char *s)
{
int sum=0;
int u=0;
for(;*s;s++)
{
int c=idx(*s);
while(u&&!ch[u][c]) u=f[u];
u=ch[u][c];
for(int tmp=u;tmp;tmp=last[tmp])
sum+=val[tmp];
}
//puts("");
return sum;
}
int search(char *s)
{
int u=0;
for(; *s; s++)
{
int c=idx(*s);
if(!ch[u][c])
return 0;
u=ch[u][c];
}
return val[u];
}
}heap,buf;
void append(int uh,int ub)
{
heap.val[uh]+=buf.val[ub];
ff(c,CH)
{
int nh=heap.ch[uh][c];
int nb=buf.ch[ub][c];
if(nb)
{
if(!nh)
{
heap.nn(uh,c);
nh=heap.ch[uh][c];
}
append(nh,nb);
}
}
}
void join()
{
append(0,0);
buf.init();
heap.getfail();
}
char s[10000005];
void move(int n)
{
//printf("->>%d\n",n);
if(!n) return;
int len=strlen(s);
n%=len;
for(int i=0;i<n;i++)
s[i+len] = s[i];
s[n+len]=0;
strcpy(s,s+n);
s[len]=0;
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
printf("Case #%d:\n",cas++);
heap.init();
buf.init();
char cmd;
int n,flag=0,sft=0;;
scanf("%d",&n);
while(n--)
{
getchar();
scanf("%c",&cmd);
scanf("%s",s);
move(sft);
if(cmd=='+')
{
if(buf.search(s)||heap.search(s)) continue;
flag++;
buf.ins(s);
if(buf.sz>2000)
join(),flag=0;
}
else
{
if(flag)
buf.getfail();
sft=heap.calc(s)+buf.calc(s);
printf("%d\n",sft);
}
}
}
return 0;
}