题意:
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
N<=2000
L1<=2000000
M<=100000
L2<=2000000
Output
输出M行,每行一个数,第i行的数表示有多少个序列拥有第i个优秀基因。
题解:
论wyc一分钟切掉的题我调了一个小时QAQ
一看就知道是trie树,于是先把原来的N个字符串建出trie树,记录一下当前节点被哪些字符串包含的范围,相当于此范围内字符串的公共前缀;
再按照字典序建出反串的可持久化trie树(这里正确的做法要按照dfs序,但是我直接排序了,理论上会TLE,但是实测过了……);
询问的时候先在第一棵trie里找s1,找不到就直接输出-1,否则记录下它被包含的范围,再将s2反过来,用求出的范围在第二颗trie中找有多少串以s2为前缀即可。
ps:trie树真好用!字符串赛高!(大雾)
代码:
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 int n,m,len,l1,l2,nw=0,cnt=0,tot=0,ans=0,rts[20001],son[2000010][26],sn[2000010][26],siz[2000010],L[2000010],R[2000010];
12 char st[2000010],ss[2000010],s1[2000010],s2[2000010];
13 struct str{
14 int l,r;
15 friend bool operator <(str a,str b){
16 int l1=a.r-a.l+1,l2=b.r-b.l+1,l=min(l1,l2);
17 for(int i=1;i<=l;i++){
18 if(st[a.l+i-1]!=st[b.l+i-1])return st[a.l+i-1]<st[b.l+i-1];
19 }
20 return l1<l2;
21 }
22 }s[2001];
23 void ins(int l,int r,int id){
24 int now=0;
25 for(int i=l;i<=r;i++){
26 if(!son[now][st[i]-'a'])son[now][st[i]-'a']=++cnt;
27 now=son[now][st[i]-'a'];
28 L[now]=min(L[now],id);
29 R[now]=max(R[now],id);
30 }
31 }
32 void _ins(int l,int r,int &u,int k){
33 u=++tot;
34 int now=u;
35 for(int i=r;i>=l;i--){
36 memcpy(sn[now],sn[k],sizeof(sn[k]));
37 sn[now][st[i]-'a']=++tot;
38 siz[now]=siz[k]+1;
39 now=sn[now][st[i]-'a'];
40 k=sn[k][st[i]-'a'];
41 }
42 siz[now]=siz[k]+1;
43 }
44 int get(char s[]){
45 int len=strlen(s+1),now=0;
46 for(int i=1;i<=len;i++){
47 if(!son[now][s1[i]-'a'])return -1;
48 now=son[now][s1[i]-'a'];
49 }
50 return now;
51 }
52 int calc(int u,int k,char s[]){
53 int len=strlen(s+1);
54 bool getd=false;
55 for(int i=len;i;i--){
56 if(!sn[k][s[i]-'a']||!siz[sn[k][s[i]-'a']]||(!getd&&siz[sn[u][s[i]]-'a']==siz[sn[k][s[i]-'a']]))return 0;
57 if(!getd)u=sn[u][s[i]-'a'];
58 if(!u)getd=true;
59 k=sn[k][s[i]-'a'];
60 }
61 return siz[k]-(getd?0:siz[u]);
62 }
63 int main(){
64 memset(L,0x7f,sizeof(L));
65 memset(R,0,sizeof(R));
66 scanf("%d",&n);
67 for(int i=1;i<=n;i++){
68 scanf("%s",ss+1);
69 len=strlen(ss+1);
70 for(int j=1;j<=len;j++)st[++nw]=ss[j];
71 s[i].l=s[i-1].r+1;
72 s[i].r=nw;
73 }
74 sort(s+1,s+n+1);
75 for(int i=1;i<=n;i++){
76 ins(s[i].l,s[i].r,i);
77 }
78 for(int i=1;i<=n;i++){
79 _ins(s[i].l,s[i].r,rts[i],rts[i-1]);
80 }
81 scanf("%d",&m);
82 for(int i=1;i<=m;i++){
83 scanf("%s%s",s1+1,s2+1);
84 l1=strlen(s1+1);
85 l2=strlen(s2+1);
86 for(int i=1;i<=l1;i++)s1[i]=(s1[i]-'a'+ans)%26+'a';
87 for(int i=1;i<=l2;i++)s2[i]=(s2[i]-'a'+ans)%26+'a';
88 //printf("%s %s
",s1+1,s2+1);
89 nw=get(s1);
90 if(nw==-1){
91 ans=0;
92 puts("0");
93 }else printf("%d
",ans=calc(rts[L[nw]-1],rts[R[nw]],s2));
94 }
95 return 0;
96 }