CF528D 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;
} 

猜你喜欢

转载自blog.csdn.net/wcy_1122/article/details/79223561