通過這題 我瞭解了何爲在線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;
}