[Codeforces 580D]Fizzy Search(FFT)
[Codeforces 580D]Fizzy Search(FFT)
题面
给定母串和模式串,字符集大小为4,给定k,模式串在某个位置匹配当且仅当任意位置模式串的这个字符所对应的母串的位置的左右k个字符之内有一个与它相同的,求模式串能全部匹配的次数。
分析
我们先考虑\(k=0\)的情况,即一般的字符串匹配。设母串为\(S\),模式串为\(T\),\(ans_i\)表示母串从\(i\)位置开始与\(T\)匹配,能够匹配的字符个数(注意:当遇到不匹配的字符时仍继续匹配,直到匹配完整个串)
\]
注意到\((p+i-1)+i\)不是常数,不符合卷积的形式。令\(T_i=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)的更多相关文章
- 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]\)中有 ...
- CodeForces - 528D Fuzzy Search (FFT求子串匹配)
题意:求母串中可以匹配模式串的子串的个数,但是每一位i的字符可以左右偏移k个位置. 分析:类似于 UVALive -4671. 用FFT求出每个字符成功匹配的个数.因为字符可以偏移k个单位,先用尺取法 ...
- Codeforces 528D Fuzzy Search(FFT)
题目 Source http://codeforces.com/problemset/problem/528/D Description Leonid works for a small and pr ...
- CodeForces 528D Fuzzy Search 多项式 FFT
原文链接http://www.cnblogs.com/zhouzhendong/p/8782849.html 题目传送门 - CodeForces 528D 题意 给你两个串$A,B(|A|\geq| ...
- 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, ...
- codeforces 528D Fuzzy Search
链接:http://codeforces.com/problemset/problem/528/D 正解:$FFT$. 很多字符串匹配的问题都可以用$FFT$来实现. 这道题是要求在左边和右边$k$个 ...
- CF528D. Fuzzy Search [FFT]
CF528D. Fuzzy Search 题意:DNA序列,在母串s中匹配模式串t,对于s中每个位置i,只要s[i-k]到s[i+k]中有c就认为匹配了c.求有多少个位置匹配了t 预处理\(f[i][ ...
- ●codeforces 528D Fuzzy Search
题链: http://codeforces.com/problemset/problem/528/D 题解: FFT 先解释一下题意: 给出两个字符串(只含'A','T','C','G'四种字符),一 ...
- Codeforces 986D Perfect Encoding FFT 分治 高精度
原文链接https://www.cnblogs.com/zhouzhendong/p/9161557.html 题目传送门 - Codeforces 986D 题意 给定一个数 $n(n\leq 10 ...
随机推荐
- 阿里云服务器安装mongodb并且启动
// 1.下载 我是直接在local里面创一个mongodb文件夹进行下载和解压 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_ ...
- 解决:npm install ERR! Unexpected end of JSON input
npm ERR! Unexpected end of JSON input npm i -g npm@5 npm install --registry=https://registry.npm.tao ...
- 移动吉比特H2-2光猫超级用户与密码
移动吉比特H2-2光猫超级用户与密码 超级用户名CMCCAdmin 密码aDm8H%MdA----------------版权声明:本文为CSDN博主「BenSon.Album」的原创文章,遵循CC ...
- go语言安装使用
go语言安装使用 下载地址 https://golang.google.cn/dl/ https://studygolang.com/dl windows https://studygolang.co ...
- elk-架构图
- intellij idea:设置java方法注释模板(intellij idea 2019.2)
一,打开方法注释模板的编辑窗口 菜单file->打开settings editor栏目下->打开Live Templates 说明:刘宏缔的架构森林是一个专注架构的博客,地址:http ...
- SOAP调用Web Service
SOAP调用Web Service (示例位置:光盘\code\ch07\ WebAppClient\ JsService4.htm) <html xmlns="http://www. ...
- C# 面试前的准备_基础知识点的回顾_03
1.HTTP中Post和Get区别 这忒简单了吧,大家是不是感觉到兴奋了,长舒一口气了,终于出现了一个可以聊上10分钟的问题了. 根据HTTP规范,Get用于信息获取,而且应该是安全的和幂等的. 参数 ...
- Shell脚本学习指南笔记(一)
脚本语言通常是解释型的,这类程序的运行.是由解释器读入程序代码,并将其转换成内部的形式, 再执行,解释器本身是一般的编译型程序. 第一行的开头处使用#!这两个字符,当内核扫描到改行的其余部分,看是否存 ...
- ES7 - 11新特性总结
es7 1 Array.prototype.includes 之前都是使用indexOf判断,没有返回-1,现在includes更加方便 Includes 方法用来检测数组中是否包含某个元素,返回bo ...