原文链接http://www.cnblogs.com/zhouzhendong/p/8782849.html

题目传送门 - CodeForces 528D

题意

  给你两个串$A,B(|A|\geq|B|)$,以及一个$k$。

  其中$A_i$与$B_j$匹配的条件是$A_{i-k\dots i+k}$中至少有一个与$B_j$相同。

  问$B$能在$A$中匹配多少次。

  字符集:$\{'A','C','G','T'\}$。

  $|B|\leq|A|\leq 2\times 10^5,k\leq 2\times 10^5$

题解

  由于我太弱了做这题又百度了真难受。

  首先我们先学习一个用$FFT$快速匹配字符串的办法$\longrightarrow$链接

  首先注意到字符集很小。

  我一开始的想法:

$$f[c]_i=[A串的第i位可以与字符c匹配]$$

$$g[c]_i=[B串的第i位可以与字符c匹配]$$

于是很容易写出卷积式子:

$$h_i=\sum_{j=0}^{i}\prod_{c\in\{'A','C','G','T'\}}(f[c]_j-g[c]_{i-j})^2$$

如果$h_i=0$则从$A$的第$i-|B|+1$个位置开始可以匹配。

但是马上发现这个式子的锅太重了。

一个是你展开之后……(你先把他展开吧QAQ)

第二个是他会因为他硕大的常数而最终GG。

  然后就求助度娘了。

  发现4个字符可以分开贡献。主要是因为$B$串只能死板匹配。

  对于一个字符$c$,

  如果$A$串的第$i$个位置可以放$c$,那么$f_i=1$,否则$f_i=0$。

  如果$B$串的第$i$个位置可以放$c$,那么$g_i=1$,否则$g_i=0$。

  然后卷积:

  $$h_i=\sum_{j=0}^i f_jg_{i-j}$$

  然后把$4$个字符的解累加起来。

  $$res_i=\sum_{c\in\{'A','C','G','T'\}}h[c]_i$$。

  显然,如果$res_i=|B|$,那么从$A$串的第$i-|B|+1$位开始可以匹配。

  然后时间复杂度还是$O((|A|+|B|)\log(|A|+|B|))$。常数小了很多,也不用自己展开了。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1<<19;
double PI=acos(-1.0);
int n,L,R[N];
struct C{
double r,i;
C(){}
C(double a,double b){r=a,i=b;}
C operator + (C x){return C(r+x.r,i+x.i);}
C operator - (C x){return C(r-x.r,i-x.i);}
C operator * (C x){return C(r*x.r-i*x.i,r*x.i+i*x.r);}
}w[N],X[N],Y[N],Z[N];
double x[N],y[N],z[N];
char str1[N],str2[N];
int cti[300];
int k,a[N],b[N],A,B,res[N];
void FFT(C a[]){
for (int i=0;i<n;i++)
if (i>R[i])
swap(a[i],a[R[i]]);
for (int t=n>>1,d=1;d<n;d<<=1,t>>=1)
for (int i=0;i<n;i+=(d<<1))
for (int j=0;j<d;j++){
C tmp=w[t*j]*a[i+j+d];
a[i+j+d]=a[i+j]-tmp;
a[i+j]=a[i+j]+tmp;
}
}
void FFT_times(double x[],double y[],double z[]){
for (int i=0;i<n;i++)
X[i]=C(x[i],0),Y[i]=C(y[i],0);
FFT(X),FFT(Y);
for (int i=0;i<n;i++)
Z[i]=X[i]*Y[i],w[i].i*=-1.0;
FFT(Z);
for (int i=0;i<n;i++)
z[i]=Z[i].r/n,w[i].i*=-1.0;
}
int main(){
cti['A']=0,cti['C']=1,cti['G']=2,cti['T']=3;
scanf("%d%d%d%s%s",&A,&B,&k,str1,str2);
for (int i=0;i<A;i++)
a[i]=cti[str1[i]];
for (int i=0;i<B;i++)
b[i]=cti[str2[i]];
for (int i=0;i<B/2;i++)
swap(b[i],b[B-i-1]);
for (n=1,L=0;n<A+B;n<<=1,L++);
for (int i=0;i<n;i++){
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
w[i]=C(cos(2*i*PI/n),sin(2*i*PI/n));
}
memset(res,0,sizeof res);
for (int i=0;i<4;i++){
for (int j=0;j<n;j++)
x[j]=y[j]=0;
int cnt=0;
for (int j=0;j<k;j++)
cnt+=a[j]==i;
for (int j=0;j<A;j++){
if (j+k<A)
cnt+=a[j+k]==i;
if (j-k-1>=0)
cnt-=a[j-k-1]==i;
x[j]=cnt>0?1:0;
}
for (int j=0;j<B;j++)
y[j]=b[j]==i?1:0;
FFT_times(x,y,z);
for (int j=B-1;j<A;j++)
res[j]+=(int)(z[j]+0.5);
}
int ans=0;
for (int i=B-1;i<A;i++)
if (res[i]==B)
ans++;
printf("%d",ans);
return 0;
}

  

CodeForces 528D Fuzzy Search 多项式 FFT的更多相关文章

  1. Codeforces 528D Fuzzy Search(FFT)

    题目 Source http://codeforces.com/problemset/problem/528/D Description Leonid works for a small and pr ...

  2. 2019.01.26 codeforces 528D. Fuzzy Search(fft)

    传送门 fftfftfft好题. 题意简述:给两个字符串s,ts,ts,t,问ttt在sss中出现了几次,字符串只由A,T,C,GA,T,C,GA,T,C,G构成. 两个字符匹配的定义: 当si−k, ...

  3. codeforces 528D Fuzzy Search

    链接:http://codeforces.com/problemset/problem/528/D 正解:$FFT$. 很多字符串匹配的问题都可以用$FFT$来实现. 这道题是要求在左边和右边$k$个 ...

  4. CodeForces - 528D Fuzzy Search (FFT求子串匹配)

    题意:求母串中可以匹配模式串的子串的个数,但是每一位i的字符可以左右偏移k个位置. 分析:类似于 UVALive -4671. 用FFT求出每个字符成功匹配的个数.因为字符可以偏移k个单位,先用尺取法 ...

  5. Codeforces.528D.Fuzzy Search(FFT)

    题目链接 \(Descripiton\) 给出文本串S和模式串T和k,S,T为DNA序列(只含\(A,T,G,C\)).对于S中的每个位置\(i\),只要\(s[i-k]\sim s[i+k]\)中有 ...

  6. ●codeforces 528D Fuzzy Search

    题链: http://codeforces.com/problemset/problem/528/D 题解: FFT 先解释一下题意: 给出两个字符串(只含'A','T','C','G'四种字符),一 ...

  7. CF 528D. Fuzzy Search NTT

    CF 528D. Fuzzy Search NTT 题目大意 给出文本串S和模式串T和k,S,T为DNA序列(只含ATGC).对于S中的每个位置\(i\),只要中[i-k,i+k]有一个位置匹配了字符 ...

  8. 【CF528D】Fuzzy Search(FFT)

    [CF528D]Fuzzy Search(FFT) 题面 给定两个只含有\(A,T,G,C\)的\(DNA\)序列 定义一个字符\(c\)可以被匹配为:它对齐的字符,在距离\(K\)以内,存在一个字符 ...

  9. CodeForces 286E Ladies' Shop 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8781889.html 题目传送门 - CodeForces 286E 题意 首先,给你$n$个数(并告诉你$m$ ...

随机推荐

  1. [BZOJ 4516] [SDOI 2016] 生成魔咒

    Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例 ...

  2. 电脑重装系统后如何恢复 Mysql 数据库

    电脑重装系统后如何恢复 Mysql 数据库 一.[设置mysql的path] 比如:我的mysql在:D:\DataBase\mysql-5.7.13-winx64,可以在环境变量中重新新建一个环境变 ...

  3. python 实现聊天室

    所用模块 asyncore 官方介绍, 源码 英文捉鸡点 这里  源码中可以看到其实本质上就对 select 以及 socket 的进一步封装 简单说明 Python的asyncore模块提供了以异步 ...

  4. 分布式监控系统开发【day38】:报警自动升级代码解析及测试(八)

    一.报警自动升级代码解析 发送邮件代码 def action_email(self,action_obj,action_operation_obj,host_id,trigger_data): ''' ...

  5. MySQL学习笔记(五)并发时经典常见的死锁原因及解决方法

    MySQL都有什么锁? MySQL有三种锁的级别:页级.表级.行级. 表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最高,并发度最低. 行级锁:开销大,加锁慢:会出现死锁:锁定粒度 ...

  6. 第六节:SignalR完结篇之依赖注入和分布式部署

    一. SignalR中DI思想的应用 DI,即依赖注入,它是一种不负责创建其自己的依赖项对象的一种模式,通常用来降低代码之间的耦合性,广泛应用于架构设计,是必不可少的一种思想. 下面结合一个需求来说一 ...

  7. 第五节:从源码的角度理解各种Result(ActionResult、JsonResult、JavaScriptResult等)

    一. 背景 提到MVC不得不说MVC中的各种Result,这些高度封装的xxxResult以及在xxxResult再度封装的xxx,大大提高了MVC框架的开发效率. 相信做过MVC开发的朋友都会用到过 ...

  8. mysql普通用户本机无法登录的解决办法

    背景 mysql和mariadb的用户表里存在匿名用户时,普通用户出现无法登录的情况 分析 先查看下用户表 mysql> select user, host, password from mys ...

  9. html设置背景图片并自适应

    <style> html{ height:100%; } body{ padding: 0; margin: 0; background: url(images/2.jpg); backg ...

  10. [简洁]JavaScript中添加、移除、移动、复制、创建和查找节点元素

    查找: document.getElementsByTagName通过标签名获取元素,不论有多少个都返回元素集合. document.getElementsByClassName通过类名获取元素,同上 ...