其他分享
首页 > 其他分享> > LG3763 [TJOI2017]DNA

LG3763 [TJOI2017]DNA

作者:互联网

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好题,枚举每个位置判断一下能否在三次以内匹配就行了。

时间复杂度\(O(n\log m)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') data=-data;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef unsigned long long ull;

co int N=1e5+1,D=131;
char a[N],b[N];
int n,m;
ull p[N],f[N],g[N];
ull ask(ull*f,int l,int r){
    return f[r]-f[l-1]*p[r-l+1];
}
int lcp(int x,int y,int r){
    int l=0;
    while(l<r){
        int mid=l+r+1>>1;
        if(ask(f,x,x+mid-1)==ask(g,y,y+mid-1)) l=mid;
        else r=mid-1;
    }
    return l;
}
bool check(int x){
    int r=x+m-1,y=1;
    for(int i=0;i<3;++i){
        int t=lcp(x,y,m-y+1);
        x+=t+1,y+=t+1;
        if(y>m) return 1;
    }
    return ask(f,x,r)==ask(g,y,m);
}
void DNA(){
    scanf("%s",a+1),n=strlen(a+1);
    scanf("%s",b+1),m=strlen(b+1);
    if(n<m) return puts("0"),void();
    for(int i=1;i<=n;++i) f[i]=f[i-1]*D+a[i];
    for(int i=1;i<=m;++i) g[i]=g[i-1]*D+b[i];
    int ans=0;
    for(int i=1;i+m-1<=n;++i)if(check(i)) ++ans;
    printf("%d\n",ans);
}
int main(){
    p[0]=1;for(int i=1;i<N;++i) p[i]=p[i-1]*D;
    for(int t=read<int>();t--;) DNA();
    return 0;
}

标签:LG3763,ch,DNA,int,S0,TJOI2017,序列,return,data
来源: https://www.cnblogs.com/autoint/p/10848414.html