【BZOJ4212】神牛的养成计划

题意:

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\n",s1+1,s2+1);
89         nw=get(s1);
90         if(nw==-1){
91             ans=0;
92             puts("0");
93         }else printf("%d\n",ans=calc(rts[L[nw]-1],rts[R[nw]],s2));
94     }
95     return 0;
96 }

 

posted @ 2018-10-21 20:56  DCDCBigBig  阅读(393)  评论(1编辑  收藏  举报