【传送门: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 ;
}

最新文章

  1. [django]Django的css、image和js静态文件生产环境配置
  2. iOS开发之XCode模拟器不能连接网络
  3. 学习Scala02 基本类型
  4. JNI文件中命名类与JAVA文件中匹配
  5. Unity之坐标转换
  6. 对称密码-分组密码-AES
  7. SQL Server 查看数据库空间分配情况的 2 种方法
  8. 减少iPhone手机系统版本号
  9. 30个HTML初学者建议
  10. 第二十六天 蛰伏的Hibernate遇到春日的暖阳 —Spring MVC 集成Hibernate使用(一)
  11. Bat脚本命令说明
  12. dummy_backend_queue.go
  13. app:利用HBuilder打包webpack项目
  14. Left Join on 多条件查询时,条件过滤的问题
  15. The Oregon Trail 俄勒冈之旅
  16. 论文阅读笔记十八:ENet: A Deep Neural Network Architecture for Real-Time Semantic Segmentation(CVPR2016)
  17. 01-jQuery的介绍
  18. BZOJ3159决战——树链剖分+非旋转treap(平衡树动态维护dfs序)
  19. 关于Hyper-V备份的四大注意事项
  20. 【BIRT】报表显示不全

热门文章

  1. 【转】 C# ListView实例:文件图标显示
  2. luogu 1865 数论 线性素数筛法
  3. HDU 5410(2015多校10)-CRB and His Birthday(全然背包)
  4. spring RestTemplate 实例(NameValuePair)
  5. 30个php操作redis经常用法代码样例
  6. springboot shiro 多realm配置认证、授权
  7. IDEA模板设置
  8. 为什么不建议用table进行布局
  9. 接口、索引器、Foreach的本质(学习笔记)
  10. 如何给table的指定td进行css样式改变