【传送门:BZOJ4259&BZOJ4503


简要题意:

  给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符

  求出第一个字符串在第二个字串中出现的次数,及出现的位置开头在第二个字符串的位置(从小到大输出)


题解:

  FFT,通配符匹配

  两道题几乎没区别

  对于两个串长度为i,它们的相似程度为$\sum_{j=0}^{i-1}(A[j]-B[j])^2$(A[j]!='*'&&B[j]!='*')

  把*设为0,则得到$\sum_{j=0}^{i-1}(A[j]-B[j])^2A[j]B[j]$

  显然只有当$\sum_{j=0}^{i-1}(A[j]-B[j])^2A[j]B[j]$为0时,A串和B串才能完全匹配

  那么对于这道题而言,设f(i)为以B的i位置为结尾的长度为n的子串与A串的相似程度

  先将n--,m--(方便写公式),然后在A后面补0

  显然$f(i)=\sum_{j=0}^{m}(A[j]-B[i-m+j])^2A[j]B[i-m+j]$

  我们把A数组翻转,就会得到$f(i)=\sum_{j=0}^{i}(A[j]-B[i-j])^2A[j]B[i-j]$

  然后把这个式子拆开就得到$f(i)=\sum_{j=0}^{i}A[j]^3B[i-j]-2*\sum_{j=0}^{i}A[j]^2B[i-j]^2+\sum_{j=0}^{i}A[j]*B[i-j]^3$

  皆大欢喜,直接三次FFT分别求就可以了


参考代码(一):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const double PI=acos(-1.0);
struct Complex
{
double r,i;
Complex(){}
Complex(double _r,double _i){r=_r;i=_i;}
friend Complex operator + (const Complex &x,const Complex &y){return Complex(x.r+y.r,x.i+y.i);}
friend Complex operator - (const Complex &x,const Complex &y){return Complex(x.r-y.r,x.i-y.i);}
friend Complex operator * (const Complex &x,const Complex &y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
}a[],b[];
int R[];
void fft(Complex *y,int len,int on)
{
for(int i=;i<len;i++) if(i<R[i]) swap(y[i],y[R[i]]);
for(int i=;i<len;i<<=)
{
Complex wn(cos(PI/i),sin(on*PI/i));
for(int j=;j<len;j+=(i<<))
{
Complex w(,);
for(int k=;k<i;k++,w=w*wn)
{
Complex u=y[j+k];
Complex v=w*y[j+k+i];
y[j+k]=u+v;
y[j+k+i]=u-v;
}
}
}
if(on==-) for(int i=;i<=len;i++) y[i].r/=len;
}
void calc(int n,int m)
{
int L=;m+=n;
for(n=;n<=m;n<<=) L++;
memset(R,,sizeof(R));
for(int i=;i<n;i++) R[i]=(R[i>>]>>)|(i&)<<(L-);
fft(a,n,);fft(b,n,);
for(int i=;i<=n;i++) a[i]=a[i]*b[i];
fft(a,n,-);
}
char s1[],s2[];
int A[],B[];
int q[];
double f[];
int main()
{
int n,m;
scanf("%d%d",&n,&m);n--;m--;
scanf("%s%s",s1,s2);
for(int i=;i<=n;i++)
{
if(s1[n-i]=='*') A[i]=;
else A[i]=s1[n-i]-'a'+;
}
for(int i=;i<=m;i++)
{
if(s2[i]=='*') B[i]=;
else B[i]=s2[i]-'a'+;
}
memset(f,,sizeof(f));
for(int i=;i<=n;i++) a[i].r=A[i]*A[i]*A[i];
for(int i=;i<=m;i++) b[i].r=B[i];
calc(n,m);
for(int i=;i<=m;i++) f[i]+=a[i].r;
memset(a,,sizeof(a));
memset(b,,sizeof(b));
for(int i=;i<=n;i++) a[i].r=A[i]*A[i];
for(int i=;i<=m;i++) b[i].r=B[i]*B[i];
calc(n,m);
for(int i=;i<=m;i++) f[i]-=2.0*a[i].r;
memset(a,,sizeof(a));
memset(b,,sizeof(b));
for(int i=;i<=n;i++) a[i].r=A[i];
for(int i=;i<=m;i++) b[i].r=B[i]*B[i]*B[i];
calc(n,m);
for(int i=;i<=m;i++) f[i]+=a[i].r;
int cnt=;
for(int i=n;i<=m;i++) if(f[i]<0.5) q[++cnt]=i-n;
printf("%d\n",cnt);
if(cnt>)
{
for(int i=;i<cnt;i++) printf("%d ",q[i]+);
printf("%d\n",q[cnt]+);
}
return ;
}

参考代码(二):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const double PI=acos(-1.0);
struct Complex
{
double r,i;
Complex(){}
Complex(double _r,double _i){r=_r;i=_i;}
friend Complex operator + (const Complex &x,const Complex &y){return Complex(x.r+y.r,x.i+y.i);}
friend Complex operator - (const Complex &x,const Complex &y){return Complex(x.r-y.r,x.i-y.i);}
friend Complex operator * (const Complex &x,const Complex &y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
}a[],b[];
int R[];
void fft(Complex *y,int len,int on)
{
for(int i=;i<len;i++) if(i<R[i]) swap(y[i],y[R[i]]);
for(int i=;i<len;i<<=)
{
Complex wn(cos(PI/i),sin(on*PI/i));
for(int j=;j<len;j+=(i<<))
{
Complex w(,);
for(int k=;k<i;k++,w=w*wn)
{
Complex u=y[j+k];
Complex v=w*y[j+k+i];
y[j+k]=u+v;
y[j+k+i]=u-v;
}
}
}
if(on==-) for(int i=;i<=len;i++) y[i].r/=len;
}
void calc(int n,int m)
{
int L=;m+=n;
for(n=;n<=m;n<<=) L++;
memset(R,,sizeof(R));
for(int i=;i<n;i++) R[i]=(R[i>>]>>)|(i&)<<(L-);
fft(a,n,);fft(b,n,);
for(int i=;i<=n;i++) a[i]=a[i]*b[i];
fft(a,n,-);
}
char s1[],s2[];
int A[],B[];
int q[];
double f[];
int main()
{
int m,n;
scanf("%s%s",s1,s2);
m=strlen(s1);n=strlen(s2);
m--;n--;
for(int i=;i<=m;i++) B[i]=s1[i]-'a'+;
for(int i=;i<=n;i++)
{
if(s2[n-i]=='?') A[i]=;
else A[i]=s2[n-i]-'a'+;
}
memset(f,,sizeof(f));
for(int i=;i<=n;i++) a[i].r=A[i]*A[i]*A[i];
for(int i=;i<=m;i++) b[i].r=B[i];
calc(n,m);
for(int i=;i<=m;i++) f[i]+=a[i].r;
memset(a,,sizeof(a));
memset(b,,sizeof(b));
for(int i=;i<=n;i++) a[i].r=A[i]*A[i];
for(int i=;i<=m;i++) b[i].r=B[i]*B[i];
calc(n,m);
for(int i=;i<=m;i++) f[i]-=2.0*a[i].r;
memset(a,,sizeof(a));
memset(b,,sizeof(b));
for(int i=;i<=n;i++) a[i].r=A[i];
for(int i=;i<=m;i++) b[i].r=B[i]*B[i]*B[i];
calc(n,m);
for(int i=;i<=m;i++) f[i]+=a[i].r;
int cnt=;
for(int i=n;i<=m;i++) if(f[i]<0.5) q[++cnt]=i-n;
printf("%d\n",cnt);
if(cnt>) for(int i=;i<=cnt;i++) printf("%d\n",q[i]);
return ;
}

BZOJ4259: 残缺的字符串 & BZOJ4503: 两个串的更多相关文章

  1. bzoj4503: 两个串 bitset

    目录 题目链接 题解 代码 题目链接 bzoj4503: 两个串 题解 暴一发bitset f[i][j] 表示 S[1..i] 是否有个后缀能匹配 T[1..j] 那么假设 S[i+1] 能匹配 T ...

  2. BZOJ4259残缺的字符串

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

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

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

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

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

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

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

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

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

  7. BZOJ4503: 两个串

    Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字符. Input 两行两个字 ...

  8. BZOJ4503 两个串 【fft】

    题目链接 BZOJ4503 题解 水水题. 和残缺的字符串那题几乎是一样的 同样转化为多项式 同样TLE 同样要手写一下复数才A #include<algorithm> #include& ...

  9. BZOJ4503 两个串 多项式 FFT

    题目传送门 - BZOJ4503 题意概括 给定两个字符串S和T,回答T在S中出现了几次,在哪些位置出现.注意T中可能有?字符,可以匹配任何字符. 题解 首先,假装你已经知道了这是一道$FFT$题. ...

随机推荐

  1. cogs 2056. 无平方因子数

    2056. 无平方因子数 ★☆   输入文件:non.in   输出文件:non.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 给出正整数n,m,区间[n,m]内的无 ...

  2. 【Linux探索之旅】第二部分第三课:文件和文件夹,组织不会亏待你

    wx_fmt=jpeg" alt="" style="max-width:100%; height:auto!important"> 内容简单介 ...

  3. 剪切具有CornerRadius的RectangleGeometry(可能在Ripple中用到)

    剪切具有CornerRadius的RectangleGeometry(可能在Ripple中用到) 1.新建Converter public class BorderClipConverter : IM ...

  4. 云server之间实时文件同步和文件备份的最简单高效的免费方案

     分布于不同云计算中心的多台云server,通常须要进行文件同步.以满足业务的须要. 传统的文件同步方案,部署繁琐.同步实时性差.无法令人惬意. 端端Clouduolc,一款纯p2p方式的文件实时 ...

  5. Transformation in kentico

    https://docs.kentico.com/k10/developing-websites/loading-and-displaying-data-on-websites/writing-tra ...

  6. nyoj--138--找球号(二)(hash+邻接表)

    找球号(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在某一国度里流行着一种游戏.游戏规则为:现有一堆球中,每个球上都有一个整数编号i(0<=i<=1 ...

  7. xBIM 基础07 创建WebBIM文件

    系列目录    [已更新最新开发文章,点击查看详细]  xBIM项目提供了一个IFC文件的Web查看器.当你想把IFC转换成紧凑的WexBIM时,需要 xBIM Essentials 和 xBIM G ...

  8. hihoCoder 1403 后缀数组 重复旋律

    思路: 后缀数组 第一次写 留个模板吧 先求出后缀数组,问题转换为询问height数组中连续k-1个数的最小值的最大值,单调队列扫描一遍即可.-yousiki 手懒用得STL //By SiriusR ...

  9. Kettle学习系列之Kettle的起源

    不多说,直接上干货! Kettle起源于十年以前,本世纪初.当时啊,ETL工具千姿百态,比较流行的工具有50个左右,ETL框架数量比工具还要多些. 根据这些工具的各自起源和功能可以分为以下4种类型,如 ...

  10. 【算法】Floyd-Warshall算法(任意两点间的最短路问题)(判断负圈)

    求解所有两点间的最短路问题叫做任意两点间的最短路问题. 可以用动态规划来解决, d[k][i][j] 表示只用前k个顶点和顶点i到顶点j的最短路径长度. 分两种情况讨论: 1.经过顶点k,  d[k] ...