题意
维护支持插入和询问的AC自动机,强制在线
题解
二进制分组(可以百度xhr的答辩论文)
对于每一个分组单独建立AC自动机,合并分组时暴力重构
还有一个细节是对于重串,要直接踢掉,可以用set或者hash判一下
因为一样的串在不同的AC自动机里出现还是当一次算
代码又慢又长…大概是string的读入拖慢速度,用时倒数…
//按我的打法原本AC自动机的初始状态各个用来模拟指针的变量都是指向根
//所以这里在数组分配每一个AC自动机时需要初始化到指向根
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<iostream>
#define N 200005
#define M 5000005
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
struct node{
int fail,lk[2];
bool mark;
inline void clear(){
lk[0]=lk[1]=fail=mark=0;
}
}ac[N];
int n,cnt,top,size,root[30],L[30],R[30];
string s,p[N];
set<string>lyf;
inline void insert(int x,int rt){
int len=p[x].length()-1,nw=rt;
for(int i=1,t;i<=len;++i){
t=p[x][i]-'0';
if(!ac[nw].lk[t]) ac[nw].lk[t]=++size;
nw=ac[nw].lk[t];
}
ac[nw].mark=1;
}
inline void build(int rt){
queue<int>q;
for(int i=0;i<=1;++i)
if(ac[rt].lk[i]!=rt){
ac[ac[rt].lk[i]].fail=rt;
q.push(ac[rt].lk[i]);
}
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<=1;++i)
if(ac[x].lk[i]!=rt){
ac[ac[x].lk[i]].fail=ac[ac[x].fail].lk[i];
q.push(ac[x].lk[i]);
}
else ac[x].lk[i]=ac[ac[x].fail].lk[i];
}
return;
}
inline void add(){
p[++cnt]=s;
L[++top]=cnt;
while(top>1&&cnt-L[top]+1==L[top]-L[top-1]) --top;
for(int i=R[top-1]+1;i<=size;++i) ac[i].clear();
root[top]=R[top-1]+1,size=root[top];
for(int i=L[top];i<=cnt;++i) insert(i,root[top]);
for(int i=root[top];i<=size;++i){
if(!ac[i].lk[0]) ac[i].lk[0]=root[top];
if(!ac[i].lk[1]) ac[i].lk[1]=root[top];
// ac[i].fail=root[top];
}
build(root[top]);
R[top]=size;
}
string tmp;
void deal(int x){
int len=s.length()-1;
x%=len;
tmp="";
for(int i=x+1;i<=len;++i) tmp+=s[i];
// cout<<tmp<<endl;
for(int i=1;i<=x;++i) tmp+=s[i];
s=s[0]+tmp;
// cout<<s<<endl;
}
int ask(int rt){
int len=s.length()-1,res=0,nw=rt;
for(int i=1,nxt;i<=len;++i){
nw=nxt=ac[nw].lk[s[i]-'0'];
while(nxt!=rt){
res+=ac[nxt].mark;
nxt=ac[nxt].fail;
}
}
return res;
}
int query(){
int res=0;
for(int i=1;i<=top;++i) res+=ask(root[i]);
return res;
}
int main(){
int test;
scanf("%d",&test);
for(int t=1;t<=test;++t){
for(int i=1;i<=size;++i) ac[i].clear();
cl(root),cl(L),cl(R);
lyf.clear();
R[0]=-1;
cnt=top=0;
size=0;
scanf("%d",&n);
int ans=0;
printf("Case #%d:\n",t);
for(int i=1;i<=n;++i){
cin>>s;
deal(ans);
if(s[0]=='+'){
int pos=lyf.count(s);
if(pos==1) continue;
lyf.insert(s);
add();
}
else printf("%d\n",ans=query());
}
}
return 0;
}