题目描述
加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在DNA链S0上的位置。所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S。
输入输出格式
输入格式:
第一行有一个数T,表示有几组数据 每组数据第一行一个长度不超过10^5的碱基序列S0
每组数据第二行一个长度不超过10^5的吃藕基因序列S
输出格式:
共T行,第i行表示第i组数据中,在S0中有多少个与S等长的连续子串可能是表现吃藕性状的碱基序列
输入输出样例
输入样例#1:
1 ATCGCCCTA CTTCA
输出样例#1:
2
说明
对于20%的数据,S0,S的长度不超过10^4
对于20%的数据,S0,S的长度不超过10^5,0<T<=10
为什么我用hash做只有40分啊, 到底哪里错了啊
1 //2018年2月28日20:29:09 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 typedef unsigned long long ull; 9 const int N = 100005; 10 const int seed = 107; 11 12 int T; 13 char a[N], b[N]; 14 ull Hash1[N], Hash2[N]; 15 ull q[N]; 16 int len1, len2; 17 18 ull get(int l, int r, ull *g){ 19 return g[r] - g[l-1] * q[r-l+1]; 20 } 21 22 23 24 int getlcp(int x1, int x2){ 25 int l = 1, r = min(len1-x1+1, len2-x2+1), res = 0; 26 while(l <= r){ 27 int mid = l+r >> 1; 28 if(get(x1, x1+mid-1, Hash1) == get(x2, x2+mid-1, Hash2)) res=mid, l=mid+1; 29 else r = mid-1; 30 } 31 return res; 32 } 33 34 bool check(int x){ 35 int y = 1, tmp; 36 for(int i=1; i<=3; i++){ 37 tmp = getlcp(x, y); 38 x += tmp + 1; y += tmp + 1; 39 if(y > len2) return true; 40 } 41 42 tmp = getlcp(x , y); 43 x += tmp; y += tmp; 44 if(y > len2) return true; 45 else return false; 46 47 } 48 49 int main(){ 50 scanf("%d", &T); 51 q[0] = 1; 52 for(int i=1; i<=10000; i++) 53 q[i] = (ull)q[i-1] * seed; 54 55 while(T--){ 56 scanf("%s", a+1); 57 scanf("%s", b+1); 58 len1 = strlen(a+1); len2 = strlen(b+1); 59 for(int i=1; i<=len1; i++) 60 Hash1[i] = Hash1[i-1]*seed + a[i]-‘A‘+1; 61 for(int i=1; i<=len2; i++) 62 Hash2[i] = Hash2[i-1]*seed + b[i]-‘A‘+1; 63 64 int ans = 0; 65 for(int i=1; i+len2-1<=len1; i++){ 66 ans += check(i); 67 } 68 printf("%d\n", ans); 69 } 70 71 return 0; 72 }