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\n",ans);
61     }
62 }
posted @ 2019-02-18 09:59  Refun  阅读(220)  评论(0编辑  收藏  举报