致去年的我:這是道廣義SAM模板題啊……ios
$1\leq N\leq 20$,$1\leq Q\leq 10^5$,字符串總長$\leq 10^6$ui
題意就是求若干個trie的最長公共子串……spa
先把全部trie並起來建廣義SAM,記錄一下每一個節點原來屬於哪一個trie,因爲$N$很小,能夠直接狀壓DP,按照parent樹從上往下轉移就行了……code
預處理答案,詢問能夠$O(1)$處理;blog
可是本題有一個坑點是廣義SAM必需要bfs創建以達到嚴格$O(n\times 字符集大小)$的時間複雜度,不然會被特殊構造的數據卡到85分。ip
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std; 10 typedef long long ll; 11 typedef double db; 12 int n,qq,t,top,len,last,cnt=1,tot=1,rt=1,rts[1000001],s1[2000001],s2[2000001],son[2000001][26],fa[2000001],mx[2000001],s[2000001],p[2000001],ch[1000001][26],ss[1000001],f[1200001]; 13 char st[1000001],nw[1000001],qr[20]; 14 queue<int>q; 15 void ins(char *s,int len,int id){ 16 int nw=rts[len-1]; 17 if(!ch[nw][s[len]-'a'])ch[nw][s[len]-'a']=++cnt; 18 ss[ch[nw][s[len]-'a']]|=id; 19 rts[len]=ch[nw][s[len]-'a']; 20 } 21 int extend(int p,int ch,int id){ 22 int np=++tot; 23 mx[np]=mx[p]+1; 24 s[np]=id; 25 for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np; 26 if(!p)fa[np]=rt; 27 else{ 28 int q=son[p][ch]; 29 if(mx[q]==mx[p]+1)fa[np]=q; 30 else{ 31 int nq=++tot; 32 s[nq]=id; 33 mx[nq]=mx[p]+1; 34 memcpy(son[nq],son[q],sizeof(son[q])); 35 fa[nq]=fa[q]; 36 fa[q]=fa[np]=nq; 37 for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq; 38 } 39 } 40 return last=np; 41 } 42 void build(){ 43 q.push(rt); 44 p[rt]=1; 45 while(!q.empty()){ 46 int u=q.front(); 47 q.pop(); 48 for(int i=0;i<26;i++){ 49 int v=ch[u][i]; 50 if(v){ 51 p[v]=extend(p[u],i,ss[v]); 52 q.push(v); 53 } 54 } 55 } 56 for(int i=1;i<=tot;i++)s1[mx[i]]++; 57 for(int i=2;i<=tot;i++)s1[i]+=s1[i-1]; 58 for(int i=1;i<=tot;i++)s2[s1[mx[i]]--]=i; 59 for(int i=tot;i;i--){ 60 s[fa[s2[i]]]|=s[s2[i]]; 61 f[s[s2[i]]]=max(f[s[s2[i]]],mx[s2[i]]); 62 } 63 } 64 int main(){ 65 scanf("%d",&n); 66 rts[0]=1; 67 for(int i=1;i<=n;i++){ 68 scanf("%s",st); 69 len=strlen(st); 70 top=0; 71 for(int j=0;j<len;j++){ 72 if(st[j]=='<')top--; 73 else{ 74 nw[++top]=st[j]; 75 ins(nw,top,1<<(i-1)); 76 } 77 } 78 } 79 build(); 80 for(int i=(1<<n)-1;i>=0;i--){ 81 for(int j=0;j<n;j++){ 82 if((1<<j)&i){ 83 f[i^(1<<j)]=max(f[i^(1<<j)],f[i]); 84 } 85 } 86 } 87 scanf("%d",&qq); 88 while(qq--){ 89 scanf("%s",qr); 90 len=strlen(qr); 91 t=0; 92 for(int i=len-1;i>=0;i--)t=t*2+qr[i]-'0'; 93 printf("%d\n",f[t]); 94 } 95 return 0; 96 }