[Codeforces 580D]Fizzy Search(FFT)

题面

给定母串和模式串,字符集大小为4,给定k,模式串在某个位置匹配当且仅当任意位置模式串的这个字符所对应的母串的位置的左右k个字符之内有一个与它相同的,求模式串能全部匹配的次数。

分析

我们先考虑\(k=0\)的情况,即一般的字符串匹配。设母串为\(S\),模式串为\(T\),\(ans_i\)表示母串从\(i\)位置开始与\(T\)匹配,能够匹配的字符个数(注意:当遇到不匹配的字符时仍继续匹配,直到匹配完整个串)

\[ans_p=\sum_{i=1}^m [S_{p+i-1}=T_i]
\]

注意到\((p+i-1)+i\)不是常数,不符合卷积的形式。令\(T_i=T_{m-i+1}\),则

\[ans_p=\sum_{i=1}^m [S_{p+i-1}=T_{m-i+1}]
\]

这样\((p+i-1)+(m-i+p)=m+p\)为常数,符合卷积的形式。但是现在仍然无法FFT处理。

容易发现,每个字符的贡献(即这个字符的匹配个数)是可加的。那么我们可以枚举字符\(c\),设\(a_{i-1}=[S_i=c],b_{m-i}=[T_i=c]\),这样\(a\)和\(b\)卷积时只有两个位置都为1的时候匹配,对答案产生1的贡献。因此\(ans_i+=(a \cdot b)_i\).枚举完字符后,只需要遍历\(ans\)序列,如果\(ans_i=m\),则说明该位置能够与\(T\)匹配

对于\(k>0\)的情况,我们只需要稍加修改\(a\)的定义。若\([i-k,i+k]\)中存在字符\(c\),则我们令\(a_{i-1}=1\),否则为0. 可以预处理前缀和来判断。这样就可以FFT了

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 1048576
#define maxc 4
using namespace std;
const double pi=acos(-1.0);
struct com{
double real;
double imag;
com(){ }
com(double _real,double _imag){
real=_real;
imag=_imag;
}
com(double x){
real=x;
imag=0;
}
void operator = (const com x){
this->real=x.real;
this->imag=x.imag;
}
void operator = (const double x){
this->real=x;
this->imag=0;
}
friend com operator + (com p,com q){
return com(p.real+q.real,p.imag+q.imag);
}
friend com operator + (com p,double q){
return com(p.real+q,p.imag);
}
void operator += (com q){
*this=*this+q;
}
void operator += (double q){
*this=*this+q;
}
friend com operator - (com p,com q){
return com(p.real-q.real,p.imag-q.imag);
}
friend com operator - (com p,double q){
return com(p.real-q,p.imag);
}
void operator -= (com q){
*this=*this-q;
}
void operator -= (double q){
*this=*this-q;
}
friend com operator * (com p,com q){
return com(p.real*q.real-p.imag*q.imag,p.real*q.imag+p.imag*q.real);
}
friend com operator * (com p,double q){
return com(p.real*q,p.imag*q);
}
void operator *= (com q){
*this=(*this)*q;
}
void operator *= (double q){
*this=(*this)*q;
}
friend com operator / (com p,double q){
return com(p.real/q,p.imag/q);
}
void operator /= (double q){
*this=(*this)/q;
}
void print(){
printf("%lf + %lf i ",real,imag);
}
};
int rev[maxn+5];
void fft(com *x,int n,int type){
for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
for(int len=1;len<n;len*=2){
int sz=len*2;
com wn1=com(cos(2*pi/sz),type*sin(2*pi/sz));
for(int l=0;l<n;l+=sz){
int r=l+len-1;
com wnk=1;
for(int i=l;i<=r;i++){
com tmp=x[i+len];
x[i+len]=x[i]-wnk*tmp;
x[i]=x[i]+wnk*tmp;
wnk=wnk*wn1;
}
}
}
if(type==-1) for(int i=0;i<n;i++) x[i]/=n;
} inline int get_id(char c){
if(c=='A') return 0;
else if(c=='T') return 1;
else if(c=='G') return 2;
else return 3;
}
int n,m,K;
char s[maxn+5],t[maxn+5];
int sum[maxc+5][maxn+5];
int match[maxn+5][maxc+5];//标记s的第i位周围有没有字符j com a[maxn+5],b[maxn+5];
long long ans[maxn+5];
int main(){
scanf("%d %d %d",&n,&m,&K);
scanf("%s",s+1);
scanf("%s",t+1);
for(int i=1;i<=n;i++){
for(int j=0;j<maxc;j++) sum[j][i]=sum[j][i-1]+(get_id(s[i])==j);
}
for(int i=1;i<=n;i++){
int lb=max(i-K,1);
int rb=min(i+K,n);
for(int j=0;j<maxc;j++){
if(sum[j][rb]-sum[j][lb-1]>0) match[i][j]=1;
else match[i][j]=0;
}
}
int M=n+m;
int N=1,L=0;
while(N<=M){
N*=2;
L++;
}
for(int i=0;i<N;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
for(int c=0;c<maxc;c++){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++){
if(match[i][c]) a[i-1]=1;
else a[i-1]=0;
}
for(int i=1;i<=m;i++){
if(get_id(t[i])==c) b[m-i]=1;
else b[m-i]=0;
}
fft(a,N,1);
fft(b,N,1);
for(int i=0;i<N;i++) a[i]*=b[i];
fft(a,N,-1);
for(int i=0;i<N;i++) ans[i]+=(long long)(a[i].real+0.5);
}
int cnt=0;
for(int i=0;i<N;i++) if(ans[i]==m) cnt++;
printf("%d\n",cnt);
}

[Codeforces 580D]Fizzy Search(FFT)的更多相关文章

  1. 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]\)中有 ...

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

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

  3. Codeforces 528D Fuzzy Search(FFT)

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

  4. CodeForces 528D Fuzzy Search 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8782849.html 题目传送门 - CodeForces 528D 题意 给你两个串$A,B(|A|\geq| ...

  5. 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, ...

  6. codeforces 528D Fuzzy Search

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

  7. CF528D. Fuzzy Search [FFT]

    CF528D. Fuzzy Search 题意:DNA序列,在母串s中匹配模式串t,对于s中每个位置i,只要s[i-k]到s[i+k]中有c就认为匹配了c.求有多少个位置匹配了t 预处理\(f[i][ ...

  8. ●codeforces 528D Fuzzy Search

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

  9. Codeforces 986D Perfect Encoding FFT 分治 高精度

    原文链接https://www.cnblogs.com/zhouzhendong/p/9161557.html 题目传送门 - Codeforces 986D 题意 给定一个数 $n(n\leq 10 ...

随机推荐

  1. 01 C语言基本介绍

    C语言特点 容易上手学习 结构化语言 执行效率高 处理的工作和活动偏底层 可以在多种计算机平台上编译(类似Java的跨平台) C语言历史 目前,C 语言是最广泛使用的系统程序设计语言之一 C 语言是最 ...

  2. Arduino PID Library

    Arduino PID Library by Brett Beauregard,contact: br3ttb@gmail.com What Is PID?   PID是什么 From  Wikipe ...

  3. Ubuntu通过iptables配置 ip 代理转发

    开启 ip 代理转发 临时开启 ip 代理转发 # 执行该命令后立即生效,但是重启后会失效 echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward 永久开启 i ...

  4. apt-get 安装软件时出现:“文件尺寸不符” 问题

    报错信息 命中:1 http://packages.deepin.com/deepin panda InRelease 命中:2 http://linux.teamviewer.com/deb sta ...

  5. shell-的特殊变量-进程状态变量$$ $! $? $_详解

    一:shell的特殊变量-进程状态变量详解  1. 进程状态变量 $$ 获取当前shell的进程号(pid) $! 执行上一个指令的pid,上一个后台运行进程的进程号 $? 获取执行上一个指令的返回值 ...

  6. 多测试讲解_009肖sirRF自动化框架安装教程

    robot framework:自动化测试框架 Python3.7 RIDE(可视化界面).  Wxpython  pip(在线下载) . setuptools(在线安装) . 第三方库 第三方库:s ...

  7. 题解:洛谷P1357 花园

    题解:洛谷P1357 花园 Description 小 L 有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为 \(1∼n\).花园 \(1\) 和 \(n\) 是相邻的. 他的环形花园每天都会换 ...

  8. MeteoInfoLab脚本示例:地图投影

    在用axesm函数创建地图坐标系的时候可以指定地图投影(设置projinfo参数),地图投影可以通过projinfo函数来创建,里面的参数依据proj4投影字符串,可以参考此网页:http://rem ...

  9. spring boot: 从配置文件中读取数据的常用方法(spring boot 2.3.4)

    一,从配置文件中读取数据有哪些方法? 通常有3种用法: 1,直接使用value注解引用得到配置项的值 2,  封装到Component类中再调用 3,  用Environment类从代码中直接访问 生 ...

  10. 插件下载地址 ext

    ext2.2.0  http://files.cnblogs.com/files/chenghu/ext-2.2.zip http://files.cnblogs.com/files/chenghu/ ...