http://www.51nod.com/onlineJudge/questionCode.html#problemId=1565&noticeId=445588

有两个基因串S和T,他们只包含AGCT四种字符。现在你要找出T在S中出现了几次。

有一个门限值k≥0。T在S的第i(1≤i≤|S|-|T|+1)个位置中出现的条件如下:把T的开头和S的第i个字符对齐,然后T中的每一个字符能够在S中找到一样的,且位置偏差不超过k的,那么就认为T在S的第i个位置中出现。也就是说对于所有的 j (1≤j≤|T|),存在一个 p (1≤p≤|S|),使得|(i+j-1)-p|≤k 和[p]=T[j]都成立。

例如,根据这样的定义"ACAT"出现在"AGCAATTCAT"的第2,3和6的位置。

如果k=0,那么这个就是经典的字符串匹配问题。

现在给定门限和两个基因串S,T,求出T在S中出现的次数。

参考:https://www.cnblogs.com/ivorysi/p/9185805.html

首先用差分/线段树处理出每个位置是否能够匹配A/T/C/G,令$a[i][j]$存之,表示$i$这个字符在$j$这个位置是否能被匹配上。

然后我们处理模式串,令$b[i][j]$表示$i$这个字符在$j$这个位置是否存在。

然后就是套路了:BZOJ4259:残缺的字符串对大部分模糊匹配都是一个套路。

我们将模式串倒置然后末尾补0,令:

$f[k][i]=\sum_{j=0}^i(b[k][j]-a[k][i-j])b[k][j]$,当$f[k][j]==0$时说明我们只看$k$字符时模式串能被以$i$为终点的字符串所匹配上。

(我们后面多乘的那个是为了防止该位置不存在$k$字符所设置的。)

展开得到:

$f[k][i]=\sum_{j=0}^ib[k][j]^2-\sum_{j=0}^ia[k][i-j]b[k][j]$

后者是一个卷积,可以直接FFT,前者的2次方其实也可以直接拿掉(因为$1^2=1,0^2=0$)

显然当所有的字符情况下均满足$f[i]==0$的时候$i$就是一个合法位点了。

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef double dl;
const int N=4e5+;
const dl pi=acos(-1.0);
const int INF=;
struct complex{
dl x,y;
complex(dl xx=0.0,dl yy=0.0){
x=xx,y=yy;
}
complex operator +(const complex &b)const{
return complex(x+b.x,y+b.y);
}
complex operator -(const complex &b)const{
return complex(x-b.x,y-b.y);
}
complex operator *(const complex &b)const{
return complex(x*b.x-y*b.y,x*b.y+y*b.x);
}
};
void FFT(complex a[],int n,int on){
for(int i=,j=n>>;i<n-;i++){
if(i<j)swap(a[i],a[j]);
int k=n>>;
while(j>=k){j-=k;k>>=;}
if(j<k)j+=k;
}
for(int i=;i<=n;i<<=){
complex res(cos(-*pi*on/i),sin(-*pi*on/i));
for(int j=;j<n;j+=i){
complex w(,);
for(int k=j;k<j+i/;k++){
complex u=a[k],t=w*a[k+i/];
a[k]=u+t;a[k+i/]=u-t;
w=w*res;
}
}
}
if(on==-)
for(int i=;i<n;i++)a[i].x/=n;
}
inline int turn(char ch){
if(ch=='A')return ;
if(ch=='G')return ;
if(ch=='C')return ;
return ;
}
char s1[N],s2[N];
int n,m,k,t[N][];
int a[][N],b[][N],ans[N];
complex A[N],B[N];
bool can[N];
int main(){
scanf("%d%d%d",&n,&m,&k);
scanf("%s%s",s1,s2);
for(int i=;i<n;i++){
int w=turn(s1[i]);
int l=max(,i-k),r=min(n-,i+k);
t[l][w]++;t[r+][w]--;
}
for(int i=;i<n;i++)
for(int j=;j<;j++){
if(i)t[i][j]+=t[i-][j];
if(t[i][j]>)a[j][i]=;
}
for(int i=;i<m;i++)b[turn(s2[m-i-])][i]=; int len=;
while(len<n)len<<=;
for(int i=;i<;i++){
for(int j=;j<n;j++)
ans[j]=(j?ans[j-]:)+b[i][j]; for(int j=;j<len;j++){
A[j]=complex(a[i][j],);
B[j]=complex(b[i][j],);
}
FFT(A,len,);FFT(B,len,);
for(int j=;j<len;j++)A[j]=A[j]*B[j];
FFT(A,len,-);
for(int j=;j<n;j++)ans[j]-=(int)(A[j].x+0.5); for(int j=;j<n;j++)if(ans[j])can[j]=;
}
int cnt=;
for(int i=m-;i<n;i++)if(!can[i])cnt++;
printf("%d\n",cnt);
return ;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

51NOD 1565:模糊搜索——题解的更多相关文章

  1. 51nod 1565 模糊搜索 FFT

    这...好强啊\(QwQ\) 思路:卷积?\(FFT\)? 提交:\(5\)次 错因:一开始的预处理写错了(竟然只错了最后几个大点)闹得我以为\(FFT\)写挂了\(QwQ\) 题解: 对四种字符分开 ...

  2. 51nod 1565模糊搜索(FFT)

    题目大意就是字符串匹配,不过有一个门限k而已 之前有提到过fft做字符串匹配,这里和之前那种有些许不同 因为只有A,C,G,T四种字符,所以就考虑构造4个01序列 例如,模板串a关于'A'的01序列中 ...

  3. 【51nod】1565 模糊搜索

    题解 这个字符集很小,我们可以把每个字符拿出来做一次匹配,把第一个字符串处理每个出现过的该字符处理成一个区间加,即最后变成第一个字符串的该位置能够匹配某字符 例如对于样例 10 4 1 AGCAATT ...

  4. 胡小兔的OI日志3 完结版

    胡小兔的 OI 日志 3 (2017.9.1 ~ 2017.10.11) 标签: 日记 查看最新 2017-09-02 51nod 1378 夹克老爷的愤怒 | 树形DP 夹克老爷逢三抽一之后,由于采 ...

  5. 51Nod1518 稳定多米诺覆盖 动态规划 插头dp 容斥原理

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1518.html 题目传送门 - 51Nod1518 题意 51Nod真是个好OJ ,题意概括的真好, ...

  6. HDU 6153 A Secret ( KMP&&DP || 拓展KMP )

    题意 : 给出两个字符串,现在需要求一个和sum,考虑第二个字符串的所有后缀,每个后缀对于这个sum的贡献是这个后缀在第一个字符串出现的次数*后缀的长度,最后输出的答案应当是 sum % 1e9+7 ...

  7. 51nod图论题解(4级,5级算法题)

    51nod图论题解(4级,5级算法题) 1805 小树 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 她发现她的树的点上都有一个标号(从1到n),这些树都在空 ...

  8. 51nod 1812 树的双直径 题解【树形DP】【贪心】

    老了-稍微麻烦一点的树形DP都想不到了. 题目描述 给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有 ...

  9. 51NOD 1773:A国的贸易——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1773 参考1:FWT讲解 https://www.cnblogs.com ...

随机推荐

  1. Date 工具类(包含常用的一些时间方法)

    package com.fh.util; import java.sql.Timestamp; import java.text.DateFormat; import java.text.ParseE ...

  2. hdu1869六度分离(floyd)

    六度分离 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  3. AirtestIDE实践一:梦幻西游手游师门任务自动化

    Airtest Project是网易自研的游戏自动化项目.Airtest IDE是这个项目的一个IDE,就像Eclipse.Pycharm一样,是一个集成开发工具.Airtest框架是一个基于Open ...

  4. git基础(2)

    三.查看提交历史日志查看·提交历史:git log 命令一个常用的选项是 -p,用来显示每次提交的内容差异. 你也可以加上 -2 来仅显示最近两次提交如果你想看到每次提交的简略的统计信息,你可以使用 ...

  5. commons-lang源码解析之StringUtils

    apache的commons工具包是平时使用最多的工具包之一,对其实现方式需要具体了解.commons-lang version 3.1 empty和blank的区别 StringUtils中判断St ...

  6. appcrawler遍历工具常用方法

    Usage: appcrawler [options] -a, --app <value> Android或者iOS的文件地址, 可以是网络地址, 赋值给appium的app选项 -c,  ...

  7. Dev c++ 调试步骤

    不能调试的时候,修改下列地方: 1.在“工具”->编译选项->”Add following commands when calling complier”下面的编辑框里写入:-g3 2.在 ...

  8. appcan打包后产生的问题总结

    以appcan为基础的项目,最终需要打包后进行调试.在调试过程中,主要的样式问题在苹果手机上,下面将这些问题总结起来,以防下次再犯. 1:ios 7 以上的手机中,状态栏与内容重叠: 问题描述:在io ...

  9. Java学习个人备忘录之异常

    概述 异常:是在运行时期发生的不正常情况. 在java中用类的形式对不正常情况进行了描述和封装对象. 描述不正常的情况的类,就称为异常类. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问 ...

  10. python执行linux命令的两种方法

    python执行linux命令有两种方法: 在此以Linux常用的ls命令为例: 方法一:使用os模块 1 2 3 shell# python >> import os >> ...