BZOJ 4212: 神牛的养成计划
4212: 神牛的养成计划
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 148 Solved: 33
[Submit][Status][Discuss]
Description
Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望......
后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的......
黄学长现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串。一个优秀的基因是两个字符串s1和s2,当且仅当s1是某序列的前缀的同时,s2是这个序列的后缀时,hzwer认为这个序列拥有这个优秀基因。
现在黄学长知道了M个优秀基因s1和s2,它们想知道对于给定的优秀基因,有多少个细胞的DNA序列拥有它。
Input
第一行:N,表示序列数
接下来N行,每行一个字符串,代表N个DNA序列,它们的总长为L1
接下来一个M,表示询问数
接下来M行,每行两个字符串s1和s2,由一个空格隔开,hzwer希望你能在线回答询问,所以s1等于“s1”的所有字符按字母表的顺序向后移动ans位(字母表是一个环),ans为上一个询问的答案,s2同理。例如ans=2 “s1”=qz
则s1=sb。对于第一个询问,ans=0
s1和s2的总长度为L2
Output
输出M行,每行一个数,第i行的数表示有多少个序列拥有第i个优秀基因。
Sample Input
10
emikuqihgokuhsywlmqemihhpgijkxdukjfmlqlwrpzgwrwozkmlixyxniutssasrriafu
emikuqihgokuookbqaaoyiorpfdetaeduogebnolonaoehthfaypbeiutssasrriafu
emikuqihgokuorocifwwymkcyqevdtglszfzgycbgnpomvlzppwrigowekufjwiiaxniutssasrriafu
emikuqihgokuorociysgfkzpgnotajcfjctjqgjeeiheqrepbpakmlixyxniutssasrriafu
emikuqihgokuorociysgfrhulymdxsqirjrfbngwszuyibuixyxniutssasrriafu
emikuqihgokuorguowwiozcgjetmyokqdrqxzigohiutssasrriafu
emikuqihgokuorociysgsczejjmlbwhandxqwknutzgdmxtiutssasrriafu
emikuqihgokuorociysgvzfcdxdiwdztolopdnboxfvqzfzxtpecxcbrklvtyxniutssasrriafu
emikuqihgokuorocsbtlyuosppxuzkjafbhsayenxsdmkmlixyxniutssasrriafu
emikuqihgokuorociysgfjvaikktsixmhaasbvnsvmkntgmoygfxypktjxjdkliixyxniutssasrriafu
10
emikuqihgokuorociysg yxniutssasrriafu
aiegqmedckgqknky eqpoowonnewbq
xfbdnjbazhdnhkhvb qrqgbnmlltlkkbtyn
bjfhrnfedlhrlolzfv qppxpoofxcr
zhdfpldcbjf stsidponnvnmmdvap
zhdfpldcbjfpjmjxdt gdstsidponnvnmmdvap
dlhjtphgfnjtnqnbhxr wxwmhtsrrzrqqhzet
bjfhrnfedlhrlolzfv frqppxpoofxcr
zhdfpldcbjf dponnvnmmdvap
ucyakgyxweakehes nondykjiiqihhyqvk
emikuqihgokuhsywlmqemihhpgijkxdukjfmlqlwrpzgwrwozkmlixyxniutssasrriafu
emikuqihgokuookbqaaoyiorpfdetaeduogebnolonaoehthfaypbeiutssasrriafu
emikuqihgokuorocifwwymkcyqevdtglszfzgycbgnpomvlzppwrigowekufjwiiaxniutssasrriafu
emikuqihgokuorociysgfkzpgnotajcfjctjqgjeeiheqrepbpakmlixyxniutssasrriafu
emikuqihgokuorociysgfrhulymdxsqirjrfbngwszuyibuixyxniutssasrriafu
emikuqihgokuorguowwiozcgjetmyokqdrqxzigohiutssasrriafu
emikuqihgokuorociysgsczejjmlbwhandxqwknutzgdmxtiutssasrriafu
emikuqihgokuorociysgvzfcdxdiwdztolopdnboxfvqzfzxtpecxcbrklvtyxniutssasrriafu
emikuqihgokuorocsbtlyuosppxuzkjafbhsayenxsdmkmlixyxniutssasrriafu
emikuqihgokuorociysgfjvaikktsixmhaasbvnsvmkntgmoygfxypktjxjdkliixyxniutssasrriafu
10
emikuqihgokuorociysg yxniutssasrriafu
aiegqmedckgqknky eqpoowonnewbq
xfbdnjbazhdnhkhvb qrqgbnmlltlkkbtyn
bjfhrnfedlhrlolzfv qppxpoofxcr
zhdfpldcbjf stsidponnvnmmdvap
zhdfpldcbjfpjmjxdt gdstsidponnvnmmdvap
dlhjtphgfnjtnqnbhxr wxwmhtsrrzrqqhzet
bjfhrnfedlhrlolzfv frqppxpoofxcr
zhdfpldcbjf dponnvnmmdvap
ucyakgyxweakehes nondykjiiqihhyqvk
Sample Output
4
7
3
5
5
1
3
5
10
4
7
3
5
5
1
3
5
10
4
HINT
N<=2000
L1<=2000000
M<=100000
L2<=2000000
Solution
先将序列串正序插入trie树,S1匹配到trie树一个节点X,那S1为其子树所有节点表示串的前缀。X的子树满足S1为其前缀。每个节点记录其包含的序列尾节点区间。
然后用DFS序转换为区间,在区间上逆序插入可持久化trie树,来匹配S2的逆序。
trie树+可持久化trie树:
复杂度O(L1+L2)。
1 #include<cstdio> 2 #include<string> 3 #include<vector> 4 #include<cstring> 5 const int len(2000),lem(2000000); 6 struct Trie{int nx[26],tag;}trie[lem+10]; 7 int tot=1,tp,sz[len+10];std::vector<int>line[len+10]; 8 int Eu[lem+10],size[lem+10],cnt; 9 struct CMTrie{int nx[26],sum;}tree[lem+10]; 10 int stot,root[len+10]; 11 int n,m,x,ans,leng[len+10],l1,l2; 12 char tmp[lem+10],s1[lem+10],s2[lem+10];std::string D[len+10]; 13 void insert(int k,int x,int l) 14 { 15 if(l==leng[x]) 16 { 17 if(!trie[k].tag)trie[k].tag=++tp; 18 line[trie[k].tag].push_back(x); 19 sz[trie[k].tag]++; 20 return ; 21 } 22 int next=(D[x][l]-'a'); 23 if(!trie[k].nx[next])trie[k].nx[next]=++tot; 24 insert(trie[k].nx[next],x,l+1); 25 } 26 int ins(int k,int x,int l) 27 { 28 if(!l) 29 { 30 tree[++stot]=tree[k]; 31 tree[stot].sum++; 32 return stot; 33 } 34 int next=(D[x][l]-'a'); 35 int tmp=ins(tree[k].nx[next],x,l-1); 36 tree[++stot]=tree[k]; 37 tree[stot].sum-=tree[tree[stot].nx[next]].sum; 38 tree[stot].nx[next]=tmp; 39 tree[stot].sum+=tree[tree[stot].nx[next]].sum; 40 return stot; 41 } 42 void dfs(int k) 43 { 44 if(trie[k].tag) 45 { 46 Eu[k]=++cnt;root[cnt]=root[cnt-1];size[k]=1; 47 for(int v=0;v<sz[trie[k].tag];v++) 48 root[cnt]=ins(root[cnt],line[trie[k].tag][v],leng[line[trie[k].tag][v]]); 49 }else Eu[k]=cnt+1; 50 for(int v=0;v<26;v++) 51 if(trie[k].nx[v]) 52 { 53 dfs(trie[k].nx[v]); 54 size[k]+=size[trie[k].nx[v]]; 55 } 56 } 57 int match(int k) 58 { 59 int l=0; 60 for(;l<=l1;l++) 61 k=trie[k].nx[s1[l]-'a']; 62 return k; 63 } 64 int match(int k1,int k2) 65 { 66 int l=l2; 67 for(;l>=0;l--) 68 k1=tree[k1].nx[s2[l]-'a'],k2=tree[k2].nx[s2[l]-'a']; 69 return tree[k1].sum-tree[k2].sum; 70 } 71 int main() 72 { 73 // freopen("C.in","r",stdin); 74 // freopen("C.out","w",stdout); 75 scanf("%d",&n); 76 for(int i=1;i<=n;i++) 77 { 78 scanf("%s",tmp); 79 D[i]=tmp;leng[i]=D[i].length()-1; 80 } 81 for(int i=1;i<=n;i++)insert(1,i,0); 82 // fprintf(stderr,"tot%d\n",tot); 83 root[0]=++stot; 84 dfs(1); 85 // fprintf(stderr,"stot%d\n",stot); 86 scanf("%d",&m); 87 for(int i=1;i<=m;i++) 88 { 89 scanf("%s%s",s1,s2); 90 l1=strlen(s1);l2=strlen(s2);l1--;l2--; 91 for(int i=0;i<=l1;i++) 92 s1[i]=char((int(s1[i]-'a')+ans)%26+(int)'a'); 93 for(int i=0;i<=l2;i++) 94 s2[i]=char((int(s2[i]-'a')+ans)%26+(int)'a'); 95 x=match(1); 96 ans=match(root[Eu[x]+size[x]-1],root[Eu[x]-1]); 97 printf("%d\n",ans); 98 } 99 return 0; 100 }