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.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. ...
随机推荐
- Android渲染器Shader:环状放射渐变渲染器RadialGradient(三)
Android渲染器Shader:环状放射渐变渲染器RadialGradient(三) Android RadialGradient渲染器提供一种环状.发散.放射形状的渐变渲染器. 写一个例子: ...
- B/S 开发和 C/S开发的区别
导读:每天都从应用中心下载很多软件安装尝试,在自己的电脑上也装了很多软件,但是,就出现了一个问题,好比QQ,为什么有了APP,还要有网站应用呢?由此,结合到自己的学习,就衍生出一个问题:C/S 开发就 ...
- UVA624 CD,01背包+打印路径,好题!
624 - CD 题意:一段n分钟的路程,磁带里有m首歌,每首歌有一个时间,求最多能听多少分钟的歌,并求出是拿几首歌. 思路:如果是求时常,直接用01背包即可,但设计到打印路径这里就用一个二维数组标记 ...
- mysql5.7.20主从和主主搭建
环境描述mysql主从和主主同步 注意事项:1)同步服务器网络联通,ping通,对方授权信息连接到对方数据库(防火墙开发3306)2)关闭SELinux3)同步前,双方数据库需要同步数据保持一致. 主 ...
- [luoguP2679] 子串(DP)
传送门 气死我了,自己YY的方法只能得70分. 一个下午都在搞这道题. 至于正解,真的不想写了. 请移步 here #include <cstdio> #define M 201 #def ...
- Tomcat绑定具体IP
https://blog.csdn.net/paomadeng/article/details/1826880
- hihocoder 1165 : 益智游戏
时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 幽香今天心情不错,正在和花田里的虫子玩一个益智游戏.这个游戏是这样的,对于一个数组A,幽香从A中选择一个数a,虫子从A中选 ...
- Spring Cloud(8):Sleuth和Zipkin的使用
场景: 某大型电商网站基于微服务架构,服务模块有几十个. 某天,测试人员报告该网站响应速度过慢.排除了网络问题之后,发现很难进一步去排除故障. 那么:如何对微服务的链路进行监控呢? Sleuth: 一 ...
- C++ Virtual 关键字
虚函数是C++中用于多态的机制.核心理念就是通过基类访问派生类定义的函数. 基类的析构含糊都必须是virtual的 虚函数只能借助于指针或者引用来达到多态的效果. 前提B类继承与A类 且foo()为虚 ...
- java获取本机机器名
java获取本机机器名 InetAddress.getLocalHost().getHostName().toString();