P3763 [TJOI2017] DNA
P3763 [TJOI2017] DNA
题目描述
加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列
输入格式a
第一行有一个整数
每组数据第一行一个长度不超过
每组数据第二行一个长度不超过
输出格式
共
说明/提示
对于
对于
注:DNA 碱基序列只有 ATCG 四种字符。
Solution:
本来以为字符集大小
首先我们思考一下如何匹配两个字符串,
当我们将两个字符串的 hash 求出来之后,
我们发现,匹配长度是满足单调性的,所以我们二分一个最大匹配长度
然后这题就做完了,时间复杂度
Code:
#include<bits/stdc++.h> #define ull unsigned long long const int N=1e5+5; const ull P=19991; using namespace std; ull h[2][N],qpow[N]; void init(){qpow[0]=1;for(int i=1;i<N;i++)qpow[i]=qpow[i-1]*P;} ull Hash(ull h[],int l,int r) { return h[r]-h[l-1]*qpow[r-l+1]; } int match_len(int st_s0,int st_s,int ed_s) { int l=1,r=ed_s-st_s+2,res=0; while(l<=r) { int mid=l+r>>1; if(Hash(h[0],st_s0,st_s0+mid-1)==Hash(h[1],st_s,st_s+mid-1))res=mid,l=mid+1;else r=mid-1; } return res; } bool check(int st_s0,int ed_s0,int st_s,int ed_s) { int len=ed_s-st_s; for(int i=1;i<=3;i++) { int k=match_len(st_s0,st_s,ed_s); st_s0+=k+1,st_s+=k+1; if(st_s>ed_s)return 1; } return Hash(h[0],st_s0,ed_s0)==Hash(h[1],st_s,ed_s); } char s[2][N]; int n,m,ans; void work() { ans=0; scanf("%s",s[0]+1);n=strlen(s[0]+1); scanf("%s",s[1]+1);m=strlen(s[1]+1); for(int i=1;i<=n;i++)h[0][i]=h[0][i-1]*P+s[0][i]; for(int i=1;i<=m;i++)h[1][i]=h[1][i-1]*P+s[1][i]; for(int i=1;i+m-1<=n;i++)if(check(i,i+m-1,1,m))ans++; printf("%d\n",ans); } int main() { //freopen("P3763.in","r",stdin); //freopen("P3763.out","w",stdout); init();int T;cin>>T; while(T--)work(); return 0; }