[TJOI2017] DNA 解题报告 (hash+二分)
Posted xxzh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[TJOI2017] DNA 解题报告 (hash+二分)相关的知识,希望对你有一定的参考价值。
题目链接:https://www.luogu.org/problemnew/show/P3763
题目大意:
给定原串S0,询问S0有多少个子串和给定串S相差不到3个字母
题解:
我们枚举S0的子串,问题转化为如何高效的判断两个串是否相差不到三个字母
考虑到数据范围,发现只能有log的时间余地
自然想到二分
solve每次找到第一个不同的位置并且返回,连续solve 4次,若S在这期间被处理完了,那么说明两个串相差不到3个字母
当然还有一些小细节
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> typedef unsigned long long ull; const int N=1e5+15; int lena,lenb; ull pin[N],haa[N],hab[N]; char a[N],b[N]; void H() { haa[0]=hab[0]=0; for (int i=1;i<=lena;i++) { haa[i]=haa[i-1]*113+a[i]-‘a‘; } for (int i=1;i<=lenb;i++) { hab[i]=hab[i-1]*113+b[i]-‘a‘; } } int solve(int x,int y) { int l=1,r=lenb; while (l<r) { int mid=l+r>>1; if ((haa[x+mid-1]-haa[x-1]*pin[mid])==(hab[y+mid-1]-hab[y-1]*pin[mid])) { l=mid+1; } else r=mid; } if (haa[x+l-1]-haa[x-1]*pin[l]!=hab[y+l-1]-hab[y-1]*pin[l]) { return l; } else return l+1; } int check(int x) { int now=1,k; for (int i=1;i<=3;i++) { k=solve(x,now); //printf("%d %d %d ",x,now,k); x+=k;now+=k; if (now>lenb) return 1; } k=solve(x,now); x+=k-2;now+=k-2; if (now>=lenb) return 1; return 0; } int main() { pin[0]=1; for (int i=1;i<=N;i++) pin[i]=pin[i-1]*113; int T; scanf("%d",&T); while (T--) { scanf("%s",a+1); scanf("%s",b+1); lena=strlen(a+1),lenb=strlen(b+1); H(); //printf("%d ",solve(2,3)); int re=0; for (int i=1;i<=lena-lenb+1;i++) { if (check(i)) re++; } printf("%d ",re); } return 0; }
以上是关于[TJOI2017] DNA 解题报告 (hash+二分)的主要内容,如果未能解决你的问题,请参考以下文章