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; }