【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

aebr
ob

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,其他的设为其在字符表中的序号。然后

\[\begin{align}
\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】残缺的字符串的更多相关文章

  1. CF528D Fuzzy Search 和 BZOJ4259 残缺的字符串

    Fuzzy Search 给你文本串 S 和模式串 T,求 S 的每个位置是否能模糊匹配上 T. 这里的模糊匹配指的是把 T 放到 S 相应位置上之后,T 中每个字符所在位置附近 k 个之内的位置上的 ...

  2. BZOJ4259残缺的字符串

    题目描述 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. ...

  3. BZOJ4259 残缺的字符串(FFT)

    两个串匹配时相匹配的位置位置差是相同的,那么翻转一个串就变成位置和相同,卷积的形式. 考虑如何使用卷积体现两个位置能否匹配.一个暴力的思路是每次只考虑一种字符,将其在一个串中设为1,并在另一个串中将不 ...

  4. BZOJ4259:残缺的字符串(FFT)

    Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...

  5. BZOJ4259 残缺的字符串 【fft】

    题目 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想 ...

  6. BZOJ4259: 残缺的字符串 & BZOJ4503: 两个串

    [传送门:BZOJ4259&BZOJ4503] 简要题意: 给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符 求出第一个字符串在第二个字 ...

  7. BZOJ4259 残缺的字符串 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8798532.html 题目传送门 - BZOJ4259 题意 给你两个串,用其中一个来匹配另一个.问从母串的那些 ...

  8. [BZOJ4259]残缺的字符串

    Description: 给定两个带通配符的串,求可能出现几次匹配,以及这些匹配位置 Hint: \(n \le 3*10^5\) Solution: 定义匹配函数 \(P(x)=\sum_{i=x} ...

  9. 2018.11.17 bzoj4259: 残缺的字符串(fft)

    传送门 fftfftfft套路题. 我们把aaa ~ zzz映射成111 ~ 262626,然后把∗*∗映射成000. 考虑对于两个长度都为nnn的字符串A,BA,BA,B. 我们定义一个差异函数di ...

  10. BZOJ4259: 残缺的字符串(FFT 字符串匹配)

    题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...

随机推荐

  1. 通过 URL 打开 Activity

    为每个 Activity 绑定一个 url 可以方便的让第三方 app 直接打开这些 Activity.也可以方便在 app 内部进行页面跳转,解耦. 背景 举一个常见的案例,假设我们有个产品 A,产 ...

  2. Spring-IOC实现【01-XML配置方式】

    IOC概念 IoC控制反转(IoC,Inversion of Control), 是一个概念,是一种思想.控制反转就 是对对象控制权的转移,从程序代码本身反转到了外部容器.把对象的创建.初始化. 销毁 ...

  3. 【学习笔记】JS经典异步操作,从闭包到async/await

    参考文献:王仕军——知乎专栏前端周刊 感谢作者的热心总结,本文在理解的基础上,根据自己能力水平作了一点小小的修改,在加深自己印象的同时也希望能和各位共同进步... 1. 异步与for循环 抛出一个问题 ...

  4. [转]Angular4---部署---将Angular项目部署到IIS上

    本文转自:https://www.cnblogs.com/kingkangstudy/p/7699710.html Angular项目部署到一个IIS服务器上 1.安装URL rewrite组件: 网 ...

  5. 图解Docker容器和镜像

    图解Docker容器和镜像 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别. 当我对Docke ...

  6. 流程控制<二>

    上一篇:Numbers.Strings.Lists 笔记<一>下一篇:数据结构-Python3.7<三> 如果需要修改迭代中的数据,建议先赋值一个副本(e.g:序列,切片复制的 ...

  7. scala中的isInstanceOf和asInstanceOf

    如果实例化了子类的对象,但是将其赋予了父类类型的变量, 在后续的过程中,又需要将父类类型的变量转换为子类类型的变量,应该如何做? Ø  首先,需要使用isInstanceOf 判断对象是否为指定类的对 ...

  8. 【Java深入研究】8、Java中Unsafe类详解

    java不能直接访问操作系统底层,而是通过本地方法来访问.Unsafe类提供了硬件级别的原子操作,主要提供了以下功能: 1.通过Unsafe类可以分配内存,可以释放内存: 类中提供的3个本地方法all ...

  9. IDEA maven 项目如何上传到私服仓库

    前言:idea maven 发布版本到私服(快照和正式版).我有个项目( jar 包源码),其他 maven 项目能直接引入依赖就最好了,所以必须将这个 jar 包源码发布到 maven 私服仓库里去 ...

  10. HTML命名规范

    一.关于选择器的命名   W3C CSS2.1的 4.1.3 节中提到:标识符(包括选择器中的元素名,类和ID)只能包含字符[a- zA-Z0-9]和ISO 10646字符编码U+00A1及以上,再加 ...