[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. [VBA原创源代码] excelhome 对花名册进行分类

    最近在学习<菜鸟谈VBA最最基础入门<原创>>,其中第22节有一个VBA编程作业,实现对花名册进行分类. 自己花了点时间,自己丫丫学步,终于实现出来. 在原创聚集地cnblog ...

  2. CF877E Danil and a Part-time Job

    题目大意: link 有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0 共有 m 次操作,操作分为两种 get 询问一个点 x 的子树里有多少个 1 pow 将一个点 x 的子树 ...

  3. Android使用Mono c#分段列表视图

    下载source code - 21.7 KB 你想知道如何把多个ListView控件放到一个布局中,但是让它们在显示时表现正确吗 多个列表项?你对它们正确滚动有问题吗?这个例子将向你展示如何组合单独 ...

  4. 实现Excel文件的上传和解析

    前言 本文思维导图 一.需求描述 实现一个页面上传excel的功能,并对excel中的内容做解析,最后存储在数据库中. 二.代码实现 需求实现思路: 先对上传的文件做校验和解析,这里我们通过Excel ...

  5. Socket编程,C语言版!

    socket编程--send函数&recv函数详解 一.send函数 ✍ 函数原型: int send( SOCKET s,char *buf,int len,int flags ); ✍ 功 ...

  6. composer使用git作为仓储

    composer.json "repositories": [ { "type":"git", "url":" ...

  7. java安全编码指南之:Thread API调用规则

    目录 简介 start一个Thread 不要使用ThreadGroup 不要使用stop()方法 wait 和 await 需要放在循环中调用 简介 java中多线程的开发中少不了使用Thread,我 ...

  8. js 如何获取浏览器的高度?

    <SCRIPT LANGUAGE="JavaScript"><!--var s = ""; s += " 网页可见区域宽:" ...

  9. Jmeter入门(4)- 注意事项

    一.中文乱码问题的解决方法 1. 将HTTP请求的内容编码改成UTF-8 2. 修改配置文件jmeter.properties 将jmeter安装目录的bin目录下的jmeter.properties ...

  10. App在后台运行时如何保存数据到sqlite数据库

    iOS程序进入后台后,是不允许读写任何文件和数据库(sqlite),但是允许读写NSUserDefault中的数据. 因此在后台时如果想存储数据,则可使用NSUserDefault(偏好设置)临时保存 ...