BZOJ4259:残缺的字符串(FFT与字符串匹配)
Input
Output
Sample Input
3 7
a*b
aebr*ob
Sample Output
2
1 5
https://www.cnblogs.com/clrs97/p/4814499.html
假设字符串是从第0位开始的,那么对于两个长度都为n的字符串A,B,定义距离函数
dis(A,B)=∑i=0n−(A[i]−B[i])[A[i]!=′∗′][B[i]!=′∗′]
dis(A,B)=∑i=0n−(A[i]−B[i])[A[i]!=′∗′][B[i]!=′∗′]
若把*号都设置为0,那么有
dis(A,B)=∑i=0n−(A[i]−B[i])2A[i]B[i]
dis(A,B)=∑i=0n−(A[i]−B[i])2A[i]B[i]
如果dis(A,B)=0dis(A,B)=,那么A和B完全匹配。 对于这个问题,假设我们枚举B的末尾位置i,设f[i]=dis(A,B[i−m+,i])f[i]=dis(A,B[i−m+,i]),那么B的这一个子串与A完全匹配,有 f[i]=∑j=0m−(A[j]−B[i−m++j])2A[j]B[i−m++j]=
f[i]=∑j=0m−(A[j]−B[i−m++j])2A[j]B[i−m++j]=
如果把A串翻转,并在后面不断补0直至和B串等长的话,那么有 f[i]===∑j=0i(A[j]−B[i−j])2A[j]B[i−j]∑j=0i(A[j]−2A[j]B[i−j]+B[i−j])A[j]B[i−j]∑j=0iA[j]3B[i−j]−∑j=0iA[j]2B[i−j]+∑j=0iA[j]B[i−j]
f[i]=∑j=0i(A[j]−B[i−j])2A[j]B[i−j]=∑j=0i(A[j]−2A[j]B[i−j]+B[i−j])A[j]B[i−j]=∑j=0iA[j]3B[i−j]−∑j=0iA[j]2B[i−j]+∑j=0iA[j]B[i−j]
显然可以分成三段做FFT求出所有的f[i],时间复杂度为O(nlogn)O(nlogn)。
思路大意就是用乘法表示一段字符串,如果为0,表示匹配。(A[i]-B[i])^2中的平方的原因是为了避免正负抵消为0。
首先需要会使用 FFT,卷积。卷积是指一个倒序,一个正序(序号之和相同)的乘积。
图一:A字符串和B字符串。
图二:B的x段去匹配A。
图三:FFT的手段是把原A反转后后面补“0”,变成A'然后求卷积:
B的第一位乘A'的最后一位;B的第二位乘A'的倒二位;B的第三位乘A'的倒三位...B的最后一位匹配A'的第一位
所以会看到B中x前面的部分(b0、b1...bx-1)其实乘的是A后面是“0”,对结果没有影响。
图四:显示的是真正参与匹配的位置,正好就是B的x部分和原来的A的全部。证明方法成立。
所以,我们用F(i)表示B中i为尾的匹配,即:F(i)=A’[0]*B[i]+A’[1]*B[i-1]+A’[2]*B[i-2]+...+A’[i]*B[0],也即两个序列里下标和为i的A’x和Bi-x相乘。
如果i>=len(A),且F(i)==0,则以i为尾的部分满足与A匹配。
(所以到现在,字符串的匹配除了常规的hash,kmp,后缀系列之外, 还遇到过bitset,FFT等牛逼技巧,当然splay维护什么的blabla,多得很啊。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
const double pi=acos(-1.0);
using namespace std;
struct complex{
double r,i;
complex(){};
complex(double rr,double ii):r(rr),i(ii){}
complex friend operator +(complex a,complex b){return (complex){a.r+b.r,a.i+b.i};}
complex friend operator -(complex a,complex b){return (complex){a.r-b.r,a.i-b.i};}
complex friend operator *(complex a,complex b){return (complex){a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r};}
}tmp[maxn];
struct DFT{
complex a[maxn];
void fft(int sz,int bg,int step,int opt){
if(sz==) return; int m=sz>>;
fft(m,bg,step<<,opt); fft(m,bg+step,step<<,opt);
complex w=complex(,),t=complex(cos(2.0*pi/sz),sin(2.0*pi*opt/sz));
for(int k=;k<m;k++)
{
int pos=*step*k;
tmp[k]=a[pos+bg]+w*a[pos+bg+step];
tmp[k+m]=a[pos+bg]-w*a[pos+bg+step];
w=w*t;
}
for(int i=;i!=sz;i++) a[i*step+bg]=tmp[i];
}
}A,B,C;
char c1[maxn],c2[maxn];
int a[maxn],b[maxn],ans[maxn];
int main(){
int n,m,len=; scanf("%d%d%s%s",&m,&n,c1,c2);
for(int i=;i<m;i++) if(c1[i]!='*') a[m--i]=c1[i]-'a'+;
for(int i=;i<n;i++) if(c2[i]!='*') b[i]=c2[i]-'a'+;
while(len<m+n+) len<<=; for(int i=;i<len;i++) A.a[i]=complex(a[i]*a[i]*a[i],), B.a[i]=complex(b[i],);
A.fft(len,,,); B.fft(len,,,);
for(int i=;i<len;i++) C.a[i]=C.a[i]+(A.a[i]*B.a[i]); for(int i=;i<len;i++) A.a[i]=complex(a[i],), B.a[i]=complex(b[i]*b[i]*b[i],);
A.fft(len,,,); B.fft(len,,,);
for(int i=;i<len;i++) C.a[i]=C.a[i]+(A.a[i]*B.a[i]); for(int i=;i<len;i++) A.a[i]=complex(a[i]*a[i],), B.a[i]=complex(b[i]*b[i],);
A.fft(len,,,); B.fft(len,,,);
for(int i=;i<len;i++) C.a[i]=C.a[i]-complex(,)*(A.a[i]*B.a[i]); C.fft(len,,,-); for(int i=m-;i<=n;i++) if(C.a[i].r<0.5) ans[++ans[]]=i-m+; printf("%d\n",ans[]);
for(int i=;i<ans[];i++) printf("%d ",ans[i]);
printf("%d\n",ans[ans[]]);
return ;
}
BZOJ4259:残缺的字符串(FFT与字符串匹配)的更多相关文章
- Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用
P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...
- BZOJ4259: 残缺的字符串(FFT 字符串匹配)
题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...
- BZOJ4259:残缺的字符串(FFT)
Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...
- P4173 残缺的字符串(FFT字符串匹配)
P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...
- P4173 残缺的字符串 fft
题意:给你两个字符串,问你第一个在第二个中出现过多少次,并输出位置,匹配时是模糊匹配*可和任意一个字符匹配 题解:fft加速字符串匹配; 假设上面的串是s,s长度为m,下面的串是p,p长度为n,先考虑 ...
- luoguP4173 残缺的字符串 FFT
luoguP4173 残缺的字符串 FFT 链接 luogu 思路 和昨天做的题几乎一样. 匹配等价于(其实我更喜欢fft从0开始) \(\sum\limits_{i=0}^{m-1}(S[i+j]- ...
- 【BZOJ4259】残缺的字符串 FFT
[BZOJ4259]残缺的字符串 Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时, ...
- BZOJ4259 残缺的字符串 【fft】
题目 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想 ...
- BZOJ4259残缺的字符串
题目描述 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. ...
随机推荐
- CodeForces 556 --Case of Fake Numbers
B. Case of Fake Numbers time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- FZU-2147-2147 A-B Game,规律题。。
Problem 2147 A-B Game Time Limit: 1000 mSec Memory Limit : 32768 KB Problem Description Fat brother ...
- 什么样的经历,才能领悟成为架构师? >>>
什么样的经历,才能领悟成为架构师? >>> 本文主要分析 SpringBoot 的启动过程. SpringBoot的版本为:2.1.0 release,最新版本. 一.时序图 还是老 ...
- bzoj 2337 高斯消元+概率DP
题目大意: 每条路径上有一个距离值,从1走到N可以得到一个所有经过路径的异或和,求这个异或和的数学期望 这道题直接去求数学期望的DP会导致很难列出多元方程组 我们可以考虑每一个二进制位从1走到N的平均 ...
- 565. Array Nesting
Problem statement: A zero-indexed array A consisting of N different integers is given. The array con ...
- hdu 2845
#include<stdio.h> #define N 200100 int f[N]; int a[N],n; int main() { int m,j,i,suma,sumb,sum ...
- NOI导刊2010提高(06) 黑匣子
题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个Black Box要处理一串命令. 命令只有两种: ...
- tiles
参考博客:https://blog.csdn.net/aosica321/article/details/68948915 https://blog.csdn.net/it_faquir/articl ...
- 解决使用FusionCharts以后从后台获取数据中文乱码的问题
在使用FusionCharts 的时候 ,发现了一个非常奇怪的问题, 一旦在页面上加入一个chart组件, 不管给不给数据, 从后台取到的数据, 中文就全变成了乱码. 由于我使用的是object ar ...
- vm 安装CentOS7
1.首先需要到CentOS官网下载CentOS7的iso镜像文件,地址http://mirrors.cn99.com/centos/7/isos/x86_64/ 这里我选择的是迅雷种子文件 2.下载完 ...