• BZOJ4892:[TJOI2017]dna(hash)


    Description

    加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在DNA链S0上的位置。所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S。

    Input

    第一行有一个数T,表示有几组数据 每组数据第一行一个长度不超过10^5的碱基序列S0
    每组数据第二行一个长度不超过10^5的吃藕基因序列S

    Output

    共T行,第i行表示第i组数据中,在S0中有多少个与S等长的连续子串可能是表现吃藕性状的碱基序列

    Sample Input

    1
    ATCGCCCTA
    CTTCA

    Sample Output

    2

    Solution

    以$S_0$的每一位为开头和$S$进行匹配,用$hash$求$lcp$然后往后蹦。

    因为题目限制所以我们只会往后蹦常数次。

    记得预处理区间$hash$要用的快速幂,复杂度$O(nlogn)$。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (100009)
     5 #define LL unsigned long long
     6 using namespace std;
     7 
     8 int T,l1,l2,ans;
     9 LL h1[N],h2[N],Q[N];
    10 char s[N],t[N];
    11 
    12 LL Qpow(LL a,int b)
    13 {
    14     LL ans=1;
    15     while (b)
    16     {
    17         if (b&1) ans=ans*a;
    18         a=a*a; b>>=1;
    19     }
    20     return ans;
    21 }
    22 
    23 LL gethash(int opt,int x,int y)
    24 {
    25     if (opt==1) return h1[y]-h1[x-1]*Q[y-x+1];
    26     else return h2[y]-h2[x-1]*Q[y-x+1];
    27 }
    28 
    29 int getlcp(int x,int y)
    30 {
    31     int l=1,r=min(l1-x+1,l2-y+1),ans=0;
    32     while (l<=r)
    33     {
    34         int mid=(l+r)>>1;
    35         if (gethash(1,x,x+mid-1)==gethash(2,y,y+mid-1)) ans=mid,l=mid+1;
    36         else r=mid-1;
    37     }
    38     return ans;
    39 }
    40 
    41 int main()
    42 {
    43     scanf("%d",&T);
    44     for (int i=1; i<=100000; ++i) Q[i]=Qpow((LL)100007,i);
    45     while (T--)
    46     {
    47         ans=0;
    48         scanf("%s%s",s+1,t+1);
    49         l1=strlen(s+1), l2=strlen(t+1);
    50         for (int i=1; i<=l1; ++i) h1[i]=h1[i-1]*100007+s[i]-'A'+1;
    51         for (int i=1; i<=l2; ++i) h2[i]=h2[i-1]*100007+t[i]-'A'+1;
    52         for (int i=1; i<=l1-l2+1; ++i)
    53         {
    54             int cnt=0;
    55             for (int j=1; j<=l2 && cnt<=3;)
    56                 if (s[i+j-1]!=t[j]) ++cnt, ++j;
    57                 else j+=getlcp(i+j-1,j);
    58             if (cnt<=3) ans++;
    59         }
    60         printf("%d
    ",ans);
    61     }
    62 }
  • 相关阅读:
    2-红帽RHEL 7起步
    1-了解开源共享精神
    5.pip安装时使用国内源,加快下载速度
    4. python-运算符(另类语法)
    海燕python学习目录,特别棒!
    1Python学习CentOS 7 Linux环境搭建
    2python脚本在window编辑后linux不能执行的问题
    3Python脚本在linux环境下头文件解释
    5G 频谱 新技术
    python -实现单例模式五种方法
  • 原文地址:https://www.cnblogs.com/refun/p/10393974.html
Copyright © 2020-2023  润新知