●HDU 4787 GRE Words Revenge
阿新 • • 發佈:2018-03-10
r+ %d size decode struct pop 就是 trie樹 pos
不妨把兩個AC自動機分別叫做A和B。
每次對於新來的模式串,我們把它加入B,並重構B自動機。
但B這個自動機有一個大小限制M,
一旦B的節點大小大於了M,我們就把B自動機的串全部放到A裏面去,並清空B自動機。
然後對於每個詢問,我們只需要在A,B裏都分別求得答案並相加即可。
而至於復雜度,就是由B自動機的那個節點數目限制M決定的。
而M的取值為sqrt(模式串總長)時,復雜度就比較好了。
不妨假設所有模式串長度為len,全部插入trie樹後節點也有len個。
由於每個新來的模式串都會重構B,而B的大小為sqrt(len),即重構代價為O(sqrt(len))
所以在B上花費的總復雜度為:O(串的個數n*sqrt(len))
由於每當B的大小為sqrt(len)時,就會把裏面的串放入A,並重構A。
而A的大小最大就是len,上述的"把B裏面的串放入A"的操作最多只會進行len/sqrt(len)=sqrt(len)次。
所以在A上花費的總復雜度為:O(len*sqrt(len))
所以實現這個在線構造AC自動機的復雜度為O(len*sqrt(len)+串的個數n*sqrt(len))
但是由於往往模式串的個數n不是很多,所以我們定義的M可以比sqrt(len)大一些,從而減小時間消耗 。
題鏈:
http://acm.hdu.edu.cn/showproblem.php?pid=4787
題解:
AC自動機(強制在線構造)
題目大意:
有兩種操作,
一種為:+S,表示增加模式串S,
另一種為:?S,表示查詢S中有多少子串為已經給出的模式串。
(同時由於輸入根據上一次的答案加密 ,所以強制在線)
(事先提一下,對於多次給出的相同模式串,是要去重的,至於怎麽去重,就隨便用trie樹或者map+string就好了。)
進入正題:
難道真的要讓AC自動機變得在線起來麽?
其實還是用普通AC自動機做的。
即每次插入一個新的串,我們都重構AC自動機。
當然,為了保證時間復雜度,我們采取用兩個AC自動機的做法:
不妨把兩個AC自動機分別叫做A和B。
每次對於新來的模式串,我們把它加入B,並重構B自動機。
但B這個自動機有一個大小限制M,
一旦B的節點大小大於了M,我們就把B自動機的串全部放到A裏面去,並清空B自動機。
然後對於每個詢問,我們只需要在A,B裏都分別求得答案並相加即可。
而至於復雜度,就是由B自動機的那個節點數目限制M決定的。
而M的取值為sqrt(模式串總長)時,復雜度就比較好了。
不妨假設所有模式串長度為len,全部插入trie樹後節點也有len個。
由於每個新來的模式串都會重構B,而B的大小為sqrt(len),即重構代價為O(sqrt(len))
所以在B上花費的總復雜度為:O(串的個數n*sqrt(len))
由於每當B的大小為sqrt(len)時,就會把裏面的串放入A,並重構A。
而A的大小最大就是len,上述的"把B裏面的串放入A"的操作最多只會進行len/sqrt(len)=sqrt(len)次。
所以在A上花費的總復雜度為:O(len*sqrt(len))
所以實現這個在線構造AC自動機的復雜度為O(len*sqrt(len)+串的個數n*sqrt(len))
但是由於往往模式串的個數n不是很多,所以我們定義的M可以比sqrt(len)大一些,從而減小時間消耗 。
代碼:
#include<bits/stdc++.h> #define MAXN 100005 #define BSIZE 2000//320 #define rint register int using namespace std; int Case,N; map<string,int>H; string Str; struct ACAM{ int size; bool tag[MAXN]; int ch[MAXN][2],fail[MAXN],sum[MAXN]; void Reset(){ for(rint i=1;i<=size;i++) tag[i]=ch[i][0]=ch[i][1]=0; size=1; } int Insert(int p,int c){ if(!ch[p][c]) ch[p][c]=++size; return ch[p][c]; } void Getfail(){ static queue<int> Q; Q.push(1); fail[1]=0; while(!Q.empty()){ int u=Q.front(); Q.pop(); tag[u]|=tag[fail[u]]; for(int c=0;c<=1;c++){ int p=fail[u]; while(p&&!ch[p][c]) p=fail[p]; if(!ch[u][c]) ch[u][c]=p?ch[p][c]:1; else{ int v=ch[u][c]; fail[v]=p?ch[p][c]:1; Q.push(v); sum[v]=tag[v]+sum[fail[v]]; } } } } void Build(char *S){ Reset(); int p=1; for(rint i=0;S[i];i++){ if(S[i]==‘+‘){ if(i!=0&&S[i-1]!=‘+‘) tag[p]=1; p=1; } else p=Insert(p,S[i]-‘0‘); } tag[p]=1; Getfail(); } int Match(char *T){ static int p,ret,q; p=1; ret=0; if(size==1) return ret; for(rint i=0;T[i];i++){ if(T[i]==‘?‘) p=1; else p=ch[p][T[i]-‘0‘]; ret+=sum[p]; } return ret; } }A,B; char S[MAXN*52]; void decode(int br,int key,char *T){ static int len,p; len=strlen(T); //key=0; for(int i=0,p=key%len;i<len;i++){ S[br+i]=T[p]; p++; if(p>=len) p-=len; } S[br+len]=0; } int main(){ static char T[MAXN*52]; scanf("%d",&Case); int ar,br,newlen,ans=0; for(int C=1;C<=Case;C++){ H.clear(); printf("Case #%d:\n",C); scanf("%d",&N); ans=ar=br=0; A.Reset(); B.Reset(); for(int i=1;i<=N;i++){ scanf(" %c",&S[br]); S[++br]=0; scanf("%s",&T[0]); decode(br,ans,T); br--; if(S[br]==‘?‘){ ans=0; ans+=A.Match(&S[br]); ans+=B.Match(&S[br]); printf("%d\n",ans); } else{ Str=&S[br]; if(H[Str]==1) continue; H[Str]=1; newlen=strlen(&S[br]); br+=newlen; if(B.size>=BSIZE){ A.Build(&S[0]); B.Reset(); ar=br; } else B.Build(&S[ar]); } } } return 0; }
●HDU 4787 GRE Words Revenge