Bzoj4503:两个串:FFT,构造
2016-04-19 07:09
387 查看
题目链接:4503:两个串
听说这样的通配符匹配问题常用FFT搞一搞?好吧蒟蒻并不会
对于这道题如果没有通配符,我们构造一个函数
这样如果s1和s2相等当且仅当f[x]=0
但是这道题有通配符,所以我们要把是通配符的位置s2[i]=0
然后变换一下公式可得:
这样有通配符的位置相应的函数值就会为0,表示可以匹配一切
但是这样没法做,于是将s2数组拧一拧,翻转过来,发现就是一个卷积之类的了,可以用FFT。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=888888;
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
struct cp{
double r,i;
cp(double _r=0,double _i=0):r(_r),i(_i){}
cp operator + (cp x){return cp(r+x.r,i+x.i);}
cp operator - (cp x){return cp(r-x.r,i-x.i);}
cp operator * (cp x){return cp(r*x.r-i*x.i,r*x.i+i*x.r);}
}A[maxn],B[maxn],C[maxn],D[maxn];
int dig[maxn],rev[maxn],N=0,L=0,a[maxn],b[maxn];
char s1[maxn],s2[maxn];
double ans[maxn];
int p[maxn],num=0;
void FFT(cp a[],int flag){
for (int i=0;i<N;++i) D[i]=a[rev[i]];
for (int i=0;i<N;++i) a[i]=D[i];
for (int i=2;i<=N;i<<=1){
cp wn(cos(2*pi/i),flag*sin(2*pi/i));
for (int k=0;k<N;k+=i){
cp w(1,0);
for (int j=k;j<k+i/2;++j){
cp x=a[j],y=a[j+i/2]*w;
a[j]=x+y; a[j+i/2]=x-y;
w=w*wn;
}
}
}if (flag==-1) for (int i=0;i<N;++i) a[i].r/=N;
}
int main(){
freopen("guess.in","r",stdin);
freopen("guess.out","w",stdout);
scanf("%s",s1); scanf("%s",s2);
int len1=strlen(s1),len2=strlen(s2);
for (int i=0;i<len1;++i) a[i]=s1[i]-'a'+1;
for (int i=0;i<len2;++i) b[len2-i-1]=s2[i]=='?'?0:s2[i]-'a'+1;
for (N=1,L=0;N<max(len1,len2);N<<=1,L++); N<<=1; L++;
for (int i=0;i<N;++i){
int len=0;
for (int t=i;t;t>>=1) dig[len++]=t&1;
for (int j=0;j<L;++j) rev[i]=(rev[i]<<1)|(dig[j]);
}
for (int i=0;i<N;++i) A[i]=cp(b[i]*b[i]*b[i],0);
for (int i=0;i<N;++i) B[i]=cp(1.0,0.0);
FFT(A,1); FFT(B,1);
for (int i=0;i<N;++i) C[i]=A[i]*B[i];
for (int i=0;i<N;++i) A[i]=cp(2*a[i],0);
for (int i=0;i<N;++i) B[i]=cp(b[i]*b[i],0);
FFT(A,1); FFT(B,1);
for (int i=0;i<N;++i) C[i]=C[i]-A[i]*B[i];
for (int i=0;i<N;++i) A[i]=cp(a[i]*a[i],0);
for (int i=0;i<N;++i) B[i]=cp(b[i],0);
FFT(A,1); FFT(B,1);
for (int i=0;i<N;++i) C[i]=C[i]+A[i]*B[i];
FFT(C,-1);
for (int i=0;i<=len1-len2;++i) if (C[i+len2-1].r<0.5) p[++num]=i;
printf("%d\n",num);
for (int i=1;i<=num;++i) printf("%d\n",p[i]);
}
听说这样的通配符匹配问题常用FFT搞一搞?好吧蒟蒻并不会
对于这道题如果没有通配符,我们构造一个函数
这样如果s1和s2相等当且仅当f[x]=0
但是这道题有通配符,所以我们要把是通配符的位置s2[i]=0
然后变换一下公式可得:
这样有通配符的位置相应的函数值就会为0,表示可以匹配一切
但是这样没法做,于是将s2数组拧一拧,翻转过来,发现就是一个卷积之类的了,可以用FFT。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=888888;
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
struct cp{
double r,i;
cp(double _r=0,double _i=0):r(_r),i(_i){}
cp operator + (cp x){return cp(r+x.r,i+x.i);}
cp operator - (cp x){return cp(r-x.r,i-x.i);}
cp operator * (cp x){return cp(r*x.r-i*x.i,r*x.i+i*x.r);}
}A[maxn],B[maxn],C[maxn],D[maxn];
int dig[maxn],rev[maxn],N=0,L=0,a[maxn],b[maxn];
char s1[maxn],s2[maxn];
double ans[maxn];
int p[maxn],num=0;
void FFT(cp a[],int flag){
for (int i=0;i<N;++i) D[i]=a[rev[i]];
for (int i=0;i<N;++i) a[i]=D[i];
for (int i=2;i<=N;i<<=1){
cp wn(cos(2*pi/i),flag*sin(2*pi/i));
for (int k=0;k<N;k+=i){
cp w(1,0);
for (int j=k;j<k+i/2;++j){
cp x=a[j],y=a[j+i/2]*w;
a[j]=x+y; a[j+i/2]=x-y;
w=w*wn;
}
}
}if (flag==-1) for (int i=0;i<N;++i) a[i].r/=N;
}
int main(){
freopen("guess.in","r",stdin);
freopen("guess.out","w",stdout);
scanf("%s",s1); scanf("%s",s2);
int len1=strlen(s1),len2=strlen(s2);
for (int i=0;i<len1;++i) a[i]=s1[i]-'a'+1;
for (int i=0;i<len2;++i) b[len2-i-1]=s2[i]=='?'?0:s2[i]-'a'+1;
for (N=1,L=0;N<max(len1,len2);N<<=1,L++); N<<=1; L++;
for (int i=0;i<N;++i){
int len=0;
for (int t=i;t;t>>=1) dig[len++]=t&1;
for (int j=0;j<L;++j) rev[i]=(rev[i]<<1)|(dig[j]);
}
for (int i=0;i<N;++i) A[i]=cp(b[i]*b[i]*b[i],0);
for (int i=0;i<N;++i) B[i]=cp(1.0,0.0);
FFT(A,1); FFT(B,1);
for (int i=0;i<N;++i) C[i]=A[i]*B[i];
for (int i=0;i<N;++i) A[i]=cp(2*a[i],0);
for (int i=0;i<N;++i) B[i]=cp(b[i]*b[i],0);
FFT(A,1); FFT(B,1);
for (int i=0;i<N;++i) C[i]=C[i]-A[i]*B[i];
for (int i=0;i<N;++i) A[i]=cp(a[i]*a[i],0);
for (int i=0;i<N;++i) B[i]=cp(b[i],0);
FFT(A,1); FFT(B,1);
for (int i=0;i<N;++i) C[i]=C[i]+A[i]*B[i];
FFT(C,-1);
for (int i=0;i<=len1-len2;++i) if (C[i+len2-1].r<0.5) p[++num]=i;
printf("%d\n",num);
for (int i=1;i<=num;++i) printf("%d\n",p[i]);
}
相关文章推荐
- JavaScript构造函数详解
- jQuery入门 构造函数
- 使用Java构造和解析Json数据的两种方法(详解二)
- 使用Java构造和解析Json数据的两种方法(详解一)
- java中的静态代码块、构造代码块、构造方法详解
- Python类方法__init__和__del__构造、析构过程分析
- 网络资料备忘录
- 谱相关的资料备忘
- 关于获得ArrayAdapter对象的细节
- 类的继承与派生
- 探讨“临时对象”(temporary object)
- 一幅图弄清DFT与DTFT,DFS的关系
- DSP Builder
- 爱立信笔试
- 爱立信笔试
- IIR与FIR数字滤器的比较
- 全相位FFT算法matlab的实
- [转]
- 20世纪10个最伟大的算法
- 后缀树的构造方法