[TJOI2017]DNA

题目描述

加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列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分啊, 到底哪里错了啊

----------------------------------------------------------------------------------

2018年3月2日22:32:03

更新, 终于AC了啊!!!!!检查了两天了....... 其实就是q数组初始化要到seed^100000, 我开小了才seed^10000,末尾少个零真的就是40分和100分的差距啊。。。。细心真的很重要!!!! 

 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<=100000; 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
", ans);
69     }
70 
71     return 0;
72 }

 

值得纪念一下

原文地址:https://www.cnblogs.com/sineagle/p/8490655.html