bzoj 1212: [HNOI2004]L语言 AC自动机+状压
为什么这道题网上所有题解写的都是N*Len的trie树的暴力啊,4E的复杂度。。。
为什么暴力还跑这么快啊TAT。。
有一个O(Len)的做法就是先把AC自动机建出来,因为每个字典串的长度很小,所以我们可以用fail树状压一发,每个节点记录一个值ss,表示这个点向前(1~10)的长度的串是不是一个字典串,这个东西延fail树递推就行了。
然后每次把每个串放AC自动机上走,同时记录一个值T表示(s(1,i-11)~s(1-(i-1)))这些串能否成为答案,如果如果T&ss!=0那么i这个点就可以成为答案。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 int n,m; 8 char s[1500000]; 9 int ch[1005][26];int cnt;int v[10005]; 10 int fail[1005];int len[1005]; 11 void insert() 12 { 13 int ln=strlen(s);int now=0; 14 for(int i=0;i<ln;i++) 15 { 16 int c=s[i]-'a'; 17 if(ch[now][c]) 18 { 19 now=ch[now][c]; 20 } 21 else 22 { 23 ch[now][c]=++cnt; 24 len[cnt]=len[now]+1; 25 now=ch[now][c]; 26 } 27 } 28 v[now]=1; 29 } 30 queue<int>q; 31 unsigned int ss[1005]; 32 void build() 33 { 34 for(int i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]); 35 while(!q.empty()) 36 { 37 int tmp=q.front();q.pop(); 38 for(int i=0;i<26;i++) 39 { 40 if(ch[tmp][i]) 41 { 42 q.push(ch[tmp][i]); 43 fail[ch[tmp][i]]=ch[fail[tmp]][i]; 44 } 45 else 46 { 47 ch[tmp][i]=ch[fail[tmp]][i]; 48 } 49 } 50 if(v[tmp])ss[tmp]=(ss[fail[tmp]]^(1<<(len[tmp]-1))); 51 else ss[tmp]=ss[fail[tmp]]; 52 } 53 return ; 54 } 55 unsigned int tmp; 56 void solve() 57 { 58 int ans=0; 59 unsigned int ssr=1; 60 int ln=strlen(s+1); 61 int now=0; 62 for(int i=1;i<=ln;i++) 63 { 64 int c=s[i]-'a'; 65 now=ch[now][c]; 66 tmp=ssr; 67 ssr<<=1; 68 if(tmp&ss[now])ans=max(ans,i),ssr^=1; 69 } 70 printf("%d\n",ans); 71 return ; 72 } 73 int main() 74 { 75 scanf("%d%d",&n,&m); 76 for(int i=1;i<=n;i++) 77 { 78 scanf("%s",s); 79 insert(); 80 } 81 build(); 82 for(int i=1;i<=m;i++) 83 { 84 scanf("%s",s+1); 85 solve(); 86 } 87 return 0; 88 }