【传送门: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. WinServer-AD域控入门

    计算机账户和用户账户的区别 域控中不需要事先建立计算机账户,但必须建立登录用户账户. 计算机只要知道域控管理员或者授权管理账户,就可以利用此账户为所有计算机加域. 计算机加域成功之后,都会在AD管理里 ...

  2. C#-单元测试知识点

    指的是软件中对最小单元进行测试的一种测试方法 开发阶段的测试发现问题并解决问题是最节省时间和成本 Ctrl+R Ctrl+A 自动化执行单元测试 查看代码覆盖率,通常要达到80,90%的代码测试覆盖率 ...

  3. HDU 1023

    卡特兰数.把进栈看成是+1,出栈看成是-1,任何时候部分和都有a1+a2+....ak>=0.求这样的数列的个数.这明显是卡特兰数的一个解释嘛.在<组合数学>这本书就有这样的原本的证 ...

  4. servlet调用的几种方式

    參见 文库/java/javaEE全新学习教程2.2节 1.通过URL调用 2通过提交表单 3超链接 4 javascript写一个函数,调用这个函数 1,首先在project的WebRoot目录下建 ...

  5. NYOJ 915 +-字符串【贪心】

    +-字符串 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描写叙述 Shiva得到了两个仅仅有加号和减号的字符串,字串长度同样.Shiva一次能够把一个加号和它相邻的减号交换 ...

  6. 揭秘Product Hunt怎样运用邮件崛起

    Product Hunt正被硅谷热议,而大家谈论Product Hunt时,经常涉及邮件营销. Product Hunt由Ryan Hoover 在2013年11月创立.鼓舞人们发现和分享新产品的站点 ...

  7. PHP中用下标符号[]去读取字符串的逻辑

    PHP中 [(下标)] 符号不仅能够应用于数组和对象,还能够应用于字符串,假设不注意非常easy出错. 比方获取一个网络接口,正常情况下会返回一个数组结构的json,经过解析之后结果为: array( ...

  8. JAVA设计模式之【桥接模式】

    桥接模式 蜡笔中颜色和型号之间存在耦合 毛笔中,颜色和型号解耦了 如果软件系统中某个类存在两个独立变化的维度,桥接模式可以将两个维度分离出来 角色 抽象类 扩充抽象类 实现类接口 提供基本操作 抽象类 ...

  9. Spark技术在京东智能供应链预测的应用——按照业务进行划分,然后利用scikit learn进行单机训练并预测

    3.3 Spark在预测核心层的应用 我们使用Spark SQL和Spark RDD相结合的方式来编写程序,对于一般的数据处理,我们使用Spark的方式与其他无异,但是对于模型训练.预测这些需要调用算 ...

  10. poj--2549--Sumsets(二分查找)

    Sumsets Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Statu ...