Description:
加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在DNA链S0上的位置。所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S。
Hint:
(n le 10^5)
Solution:
由于字符集较小
考虑分别计算每个字母的不匹配数量,再累加起来
枚举四个字母,把原串的为该字母的位置赋为1,其他赋为0,匹配串反之
这样就能不重不漏的统计出不匹配位置的数量
统计后直接输出<=3的位置
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=4e5+5,inf=1e9;
const double PI=acos(-1);
int n,m,k,lim=1,ans,l,r[mxn],cnt[mxn];
char s[mxn],t[mxn];
inline int read() {
char c=getchar(); int x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline int chkmax(int &x,int y) {if(x<y) x=y;}
inline int chkmin(int &x,int y) {if(x>y) x=y;}
struct cp {
double x,y;
cp (double xx=0,double yy=0) {x=xx,y=yy;}
friend cp operator + (cp a,cp b) {
return cp(a.x+b.x,a.y+b.y);
}
friend cp operator - (cp a,cp b) {
return cp(a.x-b.x,a.y-b.y);
}
friend cp operator * (cp a,cp b) {
return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
}a[mxn],b[mxn];
void FFT(cp *p,int opt)
{
for(int i=0;i<lim;++i)
if(i<r[i]) swap(p[i],p[r[i]]);
for(int mid=1;mid<lim;mid<<=1) {
cp wn=cp(cos(PI/mid),opt*sin(PI/mid));
for(int len=mid<<1,j=0;j<lim;j+=len) {
cp w(1,0);
for(int k=0;k<mid;++k,w=w*wn) {
cp x=p[j+k],y=w*p[j+mid+k];
p[j+k]=x+y,p[j+mid+k]=x-y;
}
}
}
}
void solve(char c) {
memset(a,0,sizeof(a)); memset(b,0,sizeof(b));
for(int i=0,las=-inf;i<n;++i) {
if(s[i]!=c) a[i]=1;
}
for(int i=0;i<m;++i) b[i].x=t[m-i-1]==c;
lim=1,l=0;
while(lim<=n+m-2) lim<<=1,++l;
for(int i=0;i<lim;++i)
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
FFT(a,1); FFT(b,1);
for(int i=0;i<=lim;++i) a[i]=a[i]*b[i];
FFT(a,-1);
for(int i=0;i<lim;++i) cnt[i]+=(int )(a[i].x/lim+0.5);
}
int main()
{
int T;
cin>>T;
while(T--) {
memset(cnt,0,sizeof(cnt)); ans=0;
scanf("%s %s",s,t); n=strlen(s),m=strlen(t);
for(int i=0;i<4;++i) solve("ACTG"[i]);
for(int i=m-1;i<n;++i) ans+=cnt[i]<=3;
printf("%d
",ans);
}
return 0;
}