zoukankan      html  css  js  c++  java
  • 【BZOJ4259】—残缺的字符串(FFT)

    BZOJ题面link

    这套路……真是绝了

    发现这个*导致我们无法使用相关的字符串算法

    定义差异函数fA,B=i=0n1(A[i]B[i])2A[i]B[i]f_{A,B}=sum_{i=0}^{n-1}(A[i]-B[i])^2A[i]*B[i]
    可以发现只有当A=BA=Bf=0f=0
    =0*=0则问题就能完美转化成判断f=0f=0

    考虑将AA翻转并补00nn
    则对于第ii位结尾的子串f=j=0i(A[j]B[ij])2A[i]B[ij]f=sum_{j=0}^{i}(A[j]-B[i-j])^2A[i]*B[i-j]
    =j=0iA[i]3B[ij]2j=0iA[i]2B[i]2+j=0iA[i]B[i]3=sum_{j=0}^{i}A[i]^3B[i-j]-2sum_{j=0}^{i}A[i]^2B[i]^2+sum_{j=0}^{i}A[i]*B[i]^3

    分别对于三个式子求一下卷积看每一位和是否为00就是了

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=300005;
    const double pi=acos(-1);
    struct plx{
    	double x,y;
    	plx(double _x=0,double _y=0):x(_x),y(_y){}
    	friend inline plx operator +(const plx &a,const plx &b){
    		return plx(a.x+b.x,a.y+b.y);
    	}
    	friend inline plx operator -(const plx &a,const plx &b){
    		return plx(a.x-b.x,a.y-b.y);
    	}
    	friend inline plx operator *(const plx &a,const plx &b){
    		return plx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
    	}
    }a[N<<2],b[N<<2];
    int lim=1,tim,rev[N<<2];
    inline void fft(plx f[],int kd){
    	for(int i=0;i<lim;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
    	for(int mid=1;mid<lim;mid<<=1){
    		plx now=plx(cos(pi/mid),kd*sin(pi/mid));
    		for(int i=0;i<lim;i+=(mid<<1)){
    			plx w=plx(1,0);
    			for(int j=0;j<mid;j++,w=w*now){
    				plx a0=f[i+j],a1=w*f[i+j+mid];
    				f[i+j]=a0+a1,f[i+j+mid]=a0-a1;
    			}
    		}
    	}
    	if(kd==-1)for(int i=0;i<lim;i++)f[i].x/=lim;
    }
    inline void clear(){
    	for(int i=0;i<lim;i++)a[i].x=a[i].y=b[i].x=b[i].y=0;
    }
    int n,m,x[N],y[N];
    ll ans[N],res[N],tot;
    char A[N],B[N];
    int main(){
    	m=read(),n=read();
    	scanf("%s",A),scanf("%s",B);
    	while(lim<=n*2)lim<<=1,tim++;
    	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(tim-1));
    	for(int i=0;i<m;i++)if(A[i]!='*')x[i]=A[i]-'a'+1;
    	for(int i=0;i<n;i++)if(B[i]!='*')y[i]=B[i]-'a'+1;
    	reverse(x,x+m);
    	for(int i=0;i<n;i++)a[i].x=x[i]*x[i]*x[i],b[i].x=y[i];
    	fft(a,1),fft(b,1);for(int i=0;i<lim;i++)a[i]=a[i]*b[i];
    	fft(a,-1);for(int i=0;i<=n;i++)ans[i]+=(ll)(a[i].x+0.5);
    	clear();
    	for(int i=0;i<n;i++)a[i].x=x[i]*x[i],b[i].x=y[i]*y[i];
    	fft(a,1),fft(b,1);for(int i=0;i<lim;i++)a[i]=a[i]*b[i];
    	fft(a,-1);for(int i=0;i<=n;i++)ans[i]-=2ll*(ll)(a[i].x+0.5);
    	clear();
    	for(int i=0;i<n;i++)a[i].x=x[i],b[i].x=y[i]*y[i]*y[i];
    	fft(a,1),fft(b,1);for(int i=0;i<lim;i++)a[i]=a[i]*b[i];
    	fft(a,-1);for(int i=0;i<=n;i++)ans[i]+=(ll)(a[i].x+0.5);
    	for(int i=m-1;i<n;i++)if(!ans[i])res[++tot]=i-m+2;
    	cout<<tot<<'
    ';
    	for(int i=1;i<=tot;i++)cout<<res[i]<<" ";
    }
    
  • 相关阅读:
    js设置奇偶行数样式
    c#简单的调试信息、日志信息输出
    调用接口
    sql日期转换格式
    .net 常用方法
    日常验证
    Js 返回页面 or 跳转页面
    .NET Core Kestrel部署HTTPS以及Docker部署HTTPS
    Linux openssl生成证书
    ASP.NET Core中使用AutoMapper实现自动转化
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145608.html
Copyright © 2011-2022 走看看