分块思路:
因为模式串和母串交叉给出,正常来说应该是,每次询问前都要getFail,这样显然会超时)
所以我们用一个小型ac自动机 buf , 每次插入都插入到 buf 中,并重建一下buf 的getFail
若buf的节点数 > 2000,则把其中节点添加到 ac自动机上
时间复杂度为 O(n*sqrt(n))
2 3 +01 +01 ?01001 3 +01 ?010 ?011
Case #1: 2 Case #2: 1 0
#pragma comment( linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<vector> #include<cstring> #include<queue> using namespace std; #define prt(k) cout<<#k" = "<<k<<endl; const int M = 500010; struct AC { int ch[M][2]; int t[M][2]; int L, root; int fail[M]; int end[M]; void init() { L=1; memset(ch,0,sizeof ch); memset(end,0,sizeof end); memset(fail,0,sizeof fail); root=0; } AC() { init(); } int id(char a) { return a-'0'; } bool search(char s[]) { int u=0; for(int i=0;s[i];i++) { u = ch[u][s[i]-'0']; if(u==0) return false; } return end[u]; } void insert(char s[]) { int u = 0; for(int i=0;s[i];i++) { int c = id(s[i]); if(!ch[u][c]) ch[u][c]=L++; u = ch[u][c]; } end[u]=1; } void BUILD() { queue<int> q; for(int i=0;i<2;i++) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()) { int r=q.front(); q.pop(); for(int c=0;c<2;c++) { int u = ch[r][c]; if(u==0) continue; q.push(u); int v = fail[r]; while(v && ch[v][c]==0) v=fail[v]; fail[u] = ch[v][c]; } } } int query(char s[]) { int j = 0, ans = 0; for(int i = 0; s[i] ; i++){ int c = s[i]-'0'; while(j && ch[j][c]==0) j = fail[j]; j = ch[j][c]; int temp = j; while(temp){ ans += end[temp]; temp = fail[temp]; } } return ans; } }; AC ac, buf; const int N = 10*M; int n, Q; char s[N], tmp[N]; void dfs(int u, int v){ for(int i = 0;i < 2;i++){ if( buf.ch[v][i] ) { int e2 = buf.ch[v][i]; if(! ac.ch[u][i]) { memset(ac.ch[ac.L], 0, sizeof(ac.ch[ac.L])); ac.ch[u][i] = ac.L++; } int e1 = ac.ch[u][i]; ac.end[e1] |= buf.end[e2]; dfs(e1, e2); } } } void join() { dfs(0,0); buf.init(); ac.BUILD(); } int main() { int re; cin>>re; int ca=1; while(re--) { cin>>Q; printf("Case #%d:\n", ca++); ac.init(); buf.init(); int L = 0; while(Q--) { scanf("%s",tmp); int len = strlen(tmp+1); s[0] = tmp[0]; for(int i=0;i<len;i++) s[i+1] = tmp[1+(i+L+len)%len]; s[len+1]=0; if(s[0]=='+') { if(buf.search(s+1) || ac.search(s+1)) continue; buf.insert(s+1); buf.BUILD(); if(buf.L>2000) join(); } else { L = buf.query(s+1) + ac.query(s+1); printf("%d\n", L); } } } return 0; }