[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. spring-boot-route(六)整合JApiDocs生成接口文档

    上一篇文章中介绍了使用Swagger生成接口文档,非常方便,功能也十分强大.如果非要说Swaager有什么缺点,想必就是注解写起来比较麻烦.如果我说有一款不用写注解,就可以生成文档的工具,你心动了吗? ...

  2. Java知识系统回顾整理01基础05控制流程06break

    一.break break:结束循环 二.练习--直接结束当前for循环 public class HelloWorld { public static void main(String[] args ...

  3. C++中数组作为形参的方法

    转载:https://blog.csdn.net/qq_33374294/article/details/90769668 原链接:https://www.cnblogs.com/abella/p/1 ...

  4. LiteOS-任务篇

    目录 前言 链接 参考 笔录草稿 基本概念 任务相关概念 LiteOS 任务运作机制 内核初始化 创建任务 创建任务有两种方案 任务相关函数 任务开发流程 创建创建任务 部分源码 例子 创建任务的任务 ...

  5. uni-app引入iconfont字体图标

    1 首先进入你的iconfont项目 很好, 看见圈圈的吗 , 我说蓝色的,记住了,选到这个 ,然后点击下载本地项目, 解压完就是这个了 ,然后把 圈起来的放到你的项目文件里面 ,记得引入的时候路径别 ...

  6. ASP。NET控件—控件如何相互关联

    介绍 这是我关于ASP系列的另一篇小文章.NET控件,它的主要焦点是揭示控件如何相互关联,涉及哪些实体,以及它们在此任务中的主要角色是什么. 动机 理解每次处理页面请求和某人在他的浏览器中获得您的we ...

  7. Nuxt|Vue仿探探/陌陌卡片式滑动|vue仿Tinder拖拽翻牌效果

    探探/Tinder是一个很火的陌生人社交App,趁着国庆假期闲暇时间倒腾了个Nuxt.js项目,项目中有个模块模仿探探滑动切换界面效果.支持左右拖拽滑动like和no like及滑动回弹效果. 一览效 ...

  8. C++里面类和对象是什么意思?

    本文章向大家介绍C++类和对象到底是什么意思?,主要包括C++类和对象到底是什么意思?使用实例.应用技巧.基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下.   C++ 是一门 ...

  9. 【不知道怎么分类】CF 819B Mister B and PR Shifts

    题目内容 洛谷链接 定义一个全排列\(p_i\)的偏移值为\(\sum_{i=1}^{n}|p[i]-i|\). 给你一个全排列,你可以从后面拿\(k\in[0,n-1]\)个数放在前面,使得该全排列 ...

  10. Python常用模块之random和time

    常用模块: time: 分为三种格式: 1.时间戳:从1970年1月1日0点0分0秒到现在经过的秒数 用于时间间隔的计算 import time print(time.time()) 2.字符串显示时 ...