Fuzzy Search
题目描述
传送门:http://codeforces.com/problemset/problem/528/D
题解
将AGTC分别考虑
考虑A字符,将S串中所有的A字符的前后k个位置都标记1
其它位置标记0
T串所有A字符都标记1
枚举S-T+1个位置暴力判定S串生成的01串在一定区间内是否和T串生成的01串相同
可以压位搞
也可以把T串翻转过来,然后就等价于判断相应位置卷积的值=T串中A的个数
将S串和T串生成的01串跑个FFT即可
其他字母同理
一个位置开始如果被四个字母同时满足则有解
代码
#include<bits/stdc++.h>
#define eps 1e-4
#define N 530005
#define Pi atan2(0,-1)
using namespace std;
int n,m,k,len,L,rev[N],s[N],sum[N],cnt,res;
char a[N],b[N];
const char h[]={'A','G','T','C'};
struct comp{
double r,i;
comp operator+(const comp &x)
const{return (comp){r+x.r,i+x.i};}
comp operator-(const comp &x)
const{return (comp){r-x.r,i-x.i};}
comp operator*(const comp &x)
const{return (comp){r*x.r-i*x.i,r*x.i+i*x.r};}
}A[N],B[N],ans[N],t[N];
void DFT(comp *x,int n,int inv)
{
for(int i=0;i<n;i++)t[rev[i]]=x[i];
for(int i=0;i<n;i++)x[i]=t[i];
for(int i=1,d=2;i<=L;i++,d<<=1)
{
comp w0=(comp){cos(2*Pi*inv/d),sin(2*Pi*inv/d)},w,u,v;
for(int j=0,k;j<n;j+=d)
for(k=j,w=(comp){1,0};k<j+(d>>1);k++,w=w*w0)
u=x[k],v=x[k+(d>>1)]*w,x[k]=u+v,x[k+(d>>1)]=u-v;
}
if(inv==-1)for(int i=0;i<n;i++)x[i].r/=n;
}
int main()
{
scanf("%d%d%d %s %s",&n,&m,&k,a+1,b+1);
for(int x=0;x<4;x++)
{
char c=h[x];cnt=0;
memset(s,0,sizeof(s));
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
for(int i=1;i<=n;i++)if(a[i]==c)
s[max(1,i-k)]++,s[min(i+k+1,n+1)]--;
for(int i=1;i<=n;i++)
{
s[i]+=s[i-1];
if(s[i])A[i]=(comp){1,0};
}
for(int i=1,j=m;i<=m;i++,j--)
if(b[i]==c)B[j]=(comp){1,0},cnt++;
for(len=1,L=0;len<=max(m,n)*2;len<<=1,L++);
for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1)<<(L-1);
DFT(A,len,1);DFT(B,len,1);
for(int i=0;i<len;i++)ans[i]=A[i]*B[i];
DFT(ans,len,-1);
for(int i=1;i<=n-m+1;i++)
if(fabs(ans[i+m].r-cnt)<eps)sum[i]++;
}
for(int i=1;i<=n-m+1;i++)
if(sum[i]==4)res++;
printf("%d\n",res);
return 0;
}