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.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. ...
随机推荐
- HDU 1426 dancing links解决数独问题
题目大意: 这是一个最简单的数独填充题目,题目保证只能产生一种数独,所以这里的初始9宫格较为稠密,可以直接dfs也没有问题 但最近练习dancing links,这类数据结构解决数独无疑效率会高很多 ...
- [luoguP1027] Car的旅行路线(Floyd)
传送门 建图麻烦,建完图搞一遍Floyd就好了. ——代码 #include <iostream> #include <cstdio> #include <cmath&g ...
- [转]maven编译时出现读取XXX时出错invalid LOC header (bad signature)
maven编译时出现读取XXX时出错invalid LOC header (bad signature) 一.发现问题右击pom.xml,run as —> maven install,会看到c ...
- SSH日志位置
# Redhat or Fedora Core: /var/log/secure # Mandrake, FreeBSD or OpenBSD: /var/log/auth.log # SuSE: / ...
- Codevs 2756 树上的路径
2756 树上的路径 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给出一棵树,求出最小的k,使得,且在树中存在 ...
- redis安装【三】
目录介绍: 0.Windows下下载安装包: 下载地址: https://redis.io/ 1.上传到linux服务器 将文件上传到192.168.2.128主机的usr/local目录下: C:\ ...
- JS变量写到HTML页面中并修改变量值(前台处理数据序号问题)
有时候我们在前台需要对序号进行处理,我们需要将JS变量写到页面中进行显示. 第一种方式:后台处理 第二种方式:JS中定义全局变量,然后进行显示,可以书写一个JS函数对不同的需要进行不同的替换,也就可以 ...
- HDU 6035 (虚树)(统计颜色)
HDU 6035 Colorful Tree Problem : 给一棵树,每个结点有一种颜色,定义每条路径的权值为这条路径上颜色的种数,询问所有路径(C(n,2)条)的权值之和. Solution ...
- AlertDialog自定义
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- ZOJ 1232 【灵活运用FLOYD】 【图DP】
题意: copy自http://blog.csdn.net/monkey_little/article/details/6637805 有A个村子和B个城堡,村子标号是1~A,城堡标号是A+1~B.马 ...