当前位置: 代码迷 >> 综合 >> hdu4787 GRE Words Revenge
  详细解决方案

hdu4787 GRE Words Revenge

热度:51   发布时间:2024-01-13 10:44:34.0

建立两个AC自动机,每次在小自动机上插入并且暴力重建,当小自动机的点数超过阈值时就把小自动机合并到大自动机上,暴力重建大自动机。注意因为要经常插入重建,需要区分trie树的边和AC自动机上补出来的边。
经过测试,阈值取 1000 比较快。但是数据比较水,所以阈值取 0 或者总串长 105 也可以过。

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
const int lim=0,maxn=100010,maxl=10000010;
int que[maxn];
struct acautomaton
{int trie[maxn][2],trans[maxn][2],fail[maxn],tag[maxn],num[maxn],tot;void clear(){for (int i=0;i<=tot;i++){for (int j=0;j<2;j++)trie[i][j]=trans[i][j]=0;tag[i]=fail[i]=num[i]=0;}tot=0;}int find(char *s,int l){int p=0;for (int i=0;i<l;i++)if (!trie[p][s[i]-'0']) return 0;else p=trie[p][s[i]-'0'];return tag[p];}void ins(char *s,int l){int p=0;for (int i=0;i<l;i++){if (!trie[p][s[i]-'0']) trie[p][s[i]-'0']=++tot;p=trie[p][s[i]-'0'];}tag[p]=1;}void init(){int hd=1,tl=0,u;for (int i=0;i<2;i++)if (trie[0][i]){trans[0][i]=trie[0][i];que[++tl]=trie[0][i];}while (hd<=tl){u=que[hd++];num[u]=tag[u]+num[fail[u]];for (int i=0;i<2;i++)if (trie[u][i]){trans[u][i]=trie[u][i];que[++tl]=trie[u][i];fail[trie[u][i]]=trans[fail[u]][i];}else trans[u][i]=trans[fail[u]][i];}}LL qry(char *s,int l){int p=0;LL ret=0;for (int i=0;i<l;i++){p=trans[p][s[i]-'0'];ret+=num[p];}return ret;}
}big,small;
void dfs(int &u,int v)
{if (!u) u=++big.tot;if (small.tag[v]) big.tag[u]=1;for (int i=0;i<2;i++)if (small.trie[v][i])dfs(big.trie[u][i],small.trie[v][i]);
}
void merge()
{for (int i=0;i<2;i++)if (small.trie[0][i])dfs(big.trie[0][i],small.trie[0][i]);
}
char s[maxl];
void solve()
{LL last=0;int p,q,l;big.clear();small.clear();scanf("%d",&q);while (q--){scanf("%s",s+1);l=strlen(s+1);for (int i=2;i<=l;i++) s[l+i-1]=s[i];p=last%(l-1)+2;if (s[1]=='+'){if (small.find(s+p,l-1)||big.find(s+p,l-1)) continue;small.ins(s+p,l-1);if (small.tot>lim){merge();big.init();small.clear();}else small.init();}else printf("%I64d\n",last=small.qry(s+p,l-1)+big.qry(s+p,l-1));}
}
int main()
{//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);int T;scanf("%d",&T);for (int K=1;K<=T;K++){printf("Case #%d:\n",K);solve();}
}