【BZOJ4259】残缺的字符串
【BZOJ4259】残缺的字符串
Description
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
Input
第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。
第二行为一个长度为m的字符串A。
第三行为一个长度为n的字符串B。
两个串均仅由小写字母和号组成,其中号表示相应位置已经残缺。
Output
第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。
若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。
Sample Input
3 7
ab
aebrob
Sample Output
2
1 5
首先带通配符的字符串匹配好像不能\(kmp\)。
这是\(NTT/FFT\)的一个经典应用。
如果\(A[i]与B[j]\)不能匹配,那么\(j-i+1\)就不能作为匹配的开头位置。
所以我们设一个函数\(\displaystyle GG(x)=\sum_{i=1}^n\sum_{j=1}^m[j-i+1==x]\cdot [A[i]与B[j]不能匹配]\)。我们发现这个函数有点像一个卷积的形式。于是我们将第一个字符串翻转(因为是\(-i\)),然后关键在于怎么构造卷积来使得不同的字符对\(GG\)函数有贡献。
我们将通配符位置的值设为0,其他的设为其在字符表中的序号。然后
\displaystyle GG(x)&=\sum_{i=1}^n\sum_{j=1}^m[j-i+1==x]\cdot (A[i]-B[j])^2A[i]B[j]\\
&=\sum_{i=1}^n\sum_{j=1}^m[j-i+1==x]\cdot(A[i]^3B[j]-2A[i]^2B[j]^2+A[i]B[j]^3)
\end{align}
\]
然后我们做3次FFT就可以了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 300005
#define Z complex<double>
#define pi acos(-1)
#define mod 998244353
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m;
char s[N],t[N];
int x[N],y[N];
Z f[N<<2],g[N<<2];
int rev[N<<2];
void FFT(Z *a,int d,int flag) {
int n=1<<d;
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int s=1;s<=d;s++) {
int len=1<<s,mid=len>>1;
Z w(cos(2*pi*flag/len),sin(2*pi*flag/len));
for(int i=0;i<n;i+=len) {
Z t(1,0);
for(int j=0;j<mid;j++,t*=w) {
Z u=a[i+j],v=t*a[i+j+mid];
a[i+j]=u+v;
a[i+j+mid]=u-v;
}
}
}
if(flag==-1) for(int i=0;i<n;i++) a[i]/=n;
}
int Match[N<<2];
void solve(int d,int flag) {
FFT(f,d,1),FFT(g,d,1);
for(int i=0;i<(1<<d);i++) f[i]*=g[i];
FFT(f,d,-1);
for(int i=0;i<(1<<d);i++) Match[i]+=flag*(ll)(f[i].real()+0.5);
}
vector<int>ans;
ll cal2(ll a) {return a*a;}
ll cal3(ll a) {return a*a*a;}
int main() {
n=Get(),m=Get();
scanf("%s",s);
scanf("%s",t);
reverse(s,s+n);
for(int i=0;i<n;i++) x[i]=s[i]=='*'?0:s[i]-'a'+1;
for(int i=0;i<m;i++) y[i]=t[i]=='*'?0:t[i]-'a'+1;
int d=ceil(log2(m+n));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i=0;i<n;i++) f[i]=Z(cal3(x[i]),0);
for(int i=0;i<m;i++) g[i]=Z(y[i],0);
solve(d,1);
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i=0;i<n;i++) f[i]=Z(x[i],0);
for(int i=0;i<m;i++) g[i]=Z(cal3(y[i]),0);
solve(d,1);
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i=0;i<n;i++) f[i]=Z(cal2(x[i]),0);
for(int i=0;i<m;i++) g[i]=Z(cal2(y[i]),0);
solve(d,-2);
for(int i=0;i<m+n;i++) if(Match[i]==0&&1<=i-n+2&&i-n+2<=m-n+1) ans.push_back(i-n+2);
cout<<ans.size()<<"\n";
for(int i=0;i<ans.size();i++) cout<<ans[i]<<" ";
return 0;
}
【BZOJ4259】残缺的字符串的更多相关文章
- CF528D Fuzzy Search 和 BZOJ4259 残缺的字符串
Fuzzy Search 给你文本串 S 和模式串 T,求 S 的每个位置是否能模糊匹配上 T. 这里的模糊匹配指的是把 T 放到 S 相应位置上之后,T 中每个字符所在位置附近 k 个之内的位置上的 ...
- BZOJ4259残缺的字符串
题目描述 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. ...
- BZOJ4259 残缺的字符串(FFT)
两个串匹配时相匹配的位置位置差是相同的,那么翻转一个串就变成位置和相同,卷积的形式. 考虑如何使用卷积体现两个位置能否匹配.一个暴力的思路是每次只考虑一种字符,将其在一个串中设为1,并在另一个串中将不 ...
- BZOJ4259:残缺的字符串(FFT)
Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...
- BZOJ4259 残缺的字符串 【fft】
题目 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想 ...
- BZOJ4259: 残缺的字符串 & BZOJ4503: 两个串
[传送门:BZOJ4259&BZOJ4503] 简要题意: 给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符 求出第一个字符串在第二个字 ...
- BZOJ4259 残缺的字符串 多项式 FFT
原文链接http://www.cnblogs.com/zhouzhendong/p/8798532.html 题目传送门 - BZOJ4259 题意 给你两个串,用其中一个来匹配另一个.问从母串的那些 ...
- [BZOJ4259]残缺的字符串
Description: 给定两个带通配符的串,求可能出现几次匹配,以及这些匹配位置 Hint: \(n \le 3*10^5\) Solution: 定义匹配函数 \(P(x)=\sum_{i=x} ...
- 2018.11.17 bzoj4259: 残缺的字符串(fft)
传送门 fftfftfft套路题. 我们把aaa ~ zzz映射成111 ~ 262626,然后把∗*∗映射成000. 考虑对于两个长度都为nnn的字符串A,BA,BA,B. 我们定义一个差异函数di ...
- BZOJ4259: 残缺的字符串(FFT 字符串匹配)
题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...
随机推荐
- 搭建oracle linux虚拟机报错解决
sysctl -P 报错解决办法问题症状修改 linux 内核文件 #vi /etc/sysctl.conf后执行sysctl -P 报错error: "net.bridge.bridge ...
- 如何编写package.json配置NodeJS项目的模块声明
在NodeJS项目中,用package.json文件来声明项目中使用的模块,这样在新的环境部署时,只要在package.json文件所在的目录执行 npm install 命令即可安装所需要的模块. ...
- POJ 3037 Skiing(如何使用SPFA求解二维最短路问题)
题目链接: https://cn.vjudge.net/problem/POJ-3037 Bessie and the rest of Farmer John's cows are taking a ...
- nfs 提高传输速度
通常挂载 nfs 的命令为: mount -t nfs -o nolock 192.168.0.124:/home/admin/rootfs /mnt 之前我一直都是用这个命令来挂载,那个传输速度啊, ...
- forfiles
关键命令就这一条了:forfiles.exe /p "D:\Kugou" /m *.tar /d -14 /c "cmd /c del @path" 这条命令的 ...
- 部署DTCMS到Jexus遇到的问题及解决思路---部署
上一篇我们环境已经准备完成,此时可以部署了,我们就以dtcms作为例子,http://bbs.dtcms.net/forum.php?mod=viewthread&tid=2420&e ...
- 二维码编码与解码类库ThoughtWorks.QRCode
官方地址:https://www.codeproject.com/Articles/20574/Open-Source-QRCode-Library 有源代码和示例程序 支持二维码编码(生成)和解码( ...
- AJAX 基本结构 数据加载
AJAX -- 网页数据异步加载 .ashx 一般处理程序 json 数据格式,在不同的语言之间传递数据 对象格式: "{"key":"value& ...
- 百度api查询多个地址的经纬度的问题
在使用百度api查询多个地址的经纬度的时候,由于百度api提供的经纬度查询方法是回调函数,并且后续操作必须等经纬度获取完成才能进行,问题就存在于怎么判断所有地点是否都回调完成了,问了之前的一个前端大佬 ...
- repository和repertory
在研究.net core的时候知道了仓储这个概念,并发现两个单词repository和repertory 两者都有仓库,储藏所,储藏的意思,repository还指知识渊博的人,repertory除了 ...