zoukankan      html  css  js  c++  java
  • 【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
    ",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 }
  • 相关阅读:
    LiveData讲解
    Android分区存储相关
    十:存储过程和函数
    九:事务
    八:约束 和分页
    七:常见的数据类型
    六:创建和管理表
    五:SQL常见的函数
    四:SQL基本语句
    二:MYSQL 数据库的安装和常见一些命名
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9826809.html
Copyright © 2011-2022 走看看