[BZOJ4259]残缺的字符串

残缺的字符串

题解

其实大部分字符串的题都可以用多项式来想,包括这道题。

于是,我们可以尝试去构造两个多项式,使其乘后的系数为0即可。

相等为0,那么我们可以用减法表示。

可‘*’可以匹配所有的符号,我们又该咋办?那不就相当于乘个0嘛。

于是,我们得到了下式:\sum_{i=1}^{len}(A_{i}-B_{i})^{2}\cdot A_{i}\cdot B_{i}

然后就可以卷积计算了。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define int LL
#define gc() getchar()
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){
	if(x<0)return -x;
	return x;
}
const int MAXN=1200005;
const double PI=acos(-1.0);
const double eps=1e-9;
int rev[MAXN];
struct complex{
    double x,y;
    complex(double _x=0,double _y=0):x(_x),y(_y){}        
	complex operator + (complex b){return complex(x+b.x,y+b.y);}
    complex operator - (complex b){return complex(x-b.x,y-b.y);}
    complex operator * (complex b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);} 
	complex operator * (double b){return complex(x*b,y*b);}   
	complex operator / (double b){return complex(x/b,y/b);}
}A[MAXN],B[MAXN];
void FFT(int lim,complex *X,int typ){
	for(int i=0;i<lim;i++)if(i<rev[i])swap(X[i],X[rev[i]]);
	for(int i=1;i<lim;i<<=1){
		complex wn=complex(cos(PI/i),typ*sin(PI/i));
		for(int j=0;j<lim;j+=(i<<1)){
			complex w(1,0);
			for(int k=0;k<i;k++,w=w*wn){
				complex x=X[j+k],y=w*X[i+j+k];
				X[j+k]=x+y;X[i+j+k]=x-y;
			}
		}
	}
	if(typ!=-1)return ;
	for(int i=0;i<lim;i++)X[i]=X[i]/lim;
}
int ln,lm,n,m,lim;
char P[MAXN],T[MAXN];
double C[MAXN];
void solve(){
	int tmp;
	for(int i=0;i<n;i++)A[i]=B[i]=complex(0,0);
	for(int i=0;i<ln;i++)
		if(P[i]!='*'){
			tmp=P[i]-'a'+1;
			A[i]=complex(tmp*tmp*tmp,0);
		}
	for(int i=0;i<lm;i++)
		if(T[i]!='*'){
			tmp=T[i]-'a'+1;
			B[i]=complex(tmp,0);
		}
	FFT(n,A,1);FFT(n,B,1);
	for(int i=0;i<n;i++)A[i]=A[i]*B[i];
	FFT(n,A,-1);
	for(int i=0;i<n;i++)C[i]=floor(A[i].x+0.5);
	for(int i=0;i<n;i++)A[i]=B[i]=complex(0,0);
	for(int i=0;i<ln;i++)
		if(P[i]!='*'){
			tmp=P[i]-'a'+1;
			A[i]=complex(tmp*tmp,0);
		}
	for(int i=0;i<lm;i++)
		if(T[i]!='*'){
			tmp=T[i]-'a'+1;
			B[i]=complex(tmp*tmp,0);
		}
	FFT(n,A,1);FFT(n,B,1);
	for(int i=0;i<n;i++)A[i]=A[i]*B[i];
	FFT(n,A,-1);
	for(int i=0;i<n;i++)C[i]-=2*floor(A[i].x+0.5);
	for(int i=0;i<n;i++)A[i]=B[i]=complex(0,0);
	for(int i=0;i<ln;i++)
		if(P[i]!='*'){
			tmp=P[i]-'a'+1;
			A[i]=complex(tmp,0);
		}
	for(int i=0;i<lm;i++)
		if(T[i]!='*'){
			tmp=T[i]-'a'+1;
			B[i]=complex(tmp*tmp*tmp,0);
		}
	FFT(n,A,1);FFT(n,B,1);
	for(int i=0;i<n;i++)A[i]=A[i]*B[i];
	FFT(n,A,-1);
	for(int i=0;i<n;i++)C[i]+=floor(A[i].x+0.5); 
}
int ansi,ans[MAXN];
signed main(){
	read(ln);read(lm);
	scanf("%s",P);scanf("%s",T);
	for(int i=0;i<(ln>>1);i++)swap(P[i],P[ln-i-1]);
	m=ln+lm-2;n=1;while(n<=m)n<<=1,lim++;
	for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lim-1));
	solve();
	for(int i=0;i<=m;i++)
		if(Fabs(C[i])<eps&&i-ln+2>0&&i-ln+2<=lm-ln+1){
			ans[++ansi]=i-ln+2;
		}
	printf("%d\n",ansi);
	for(int i=1;i<=ansi;i++)printf("%d ",ans[i]);
    return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值