zoukankan      html  css  js  c++  java
  • BZOJ4259 残缺的字符串 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8798532.html

    题目传送门 - BZOJ4259

    题意

      给你两个串,用其中一个来匹配另一个。问从母串的那些位置开始可以匹配模式串。注意有"*"可以匹配任何字符。

      串长$leq 3 imes 10^5$。

    题解

      本题和BZOJ4503几乎一毛一样。

      这里直接放BZOJ4503的传送门。
      http://www.cnblogs.com/zhouzhendong/p/8536065.html

      但是这题要略微卡一卡时间和空间。

      这题让我第一次感受到了寻址的效率之慢。

      通过测试,同样是访问大约$8400000$个地址,仅通过改变访问顺序,我可以测出最快访问速度大约13倍的最慢访问速度。就是通过改变访问$8400000$个位置的顺序,使得$460MS ightarrow 5500MS$(谢谢BZOJ测评器,如果我选紫荆花之恋来测试的话可能得到的数据会更好哈哈,但我不敢)。(但这个应该不是上限)

      真的是QAQ。

      我写的$FFT$中对$w_{t imes j}$的寻址特别慢,所以导致效率慢了约$3000MS$。写成$Claris$的写法,可以把我的程序卡到$5000MS$(虽然精度会稍微差一点但是可以承受)。

    代码

    #include <bits/stdc++.h>
    #define y1 ______y1
    using namespace std;
    typedef long long LL;
    const int N=1<<20;
    const double PI=acos(-1.0);
    int n,L,R[N];
    struct C{
    	double r,i;
    	C(){}
    	C(double a,double b){r=a,i=b;}
    	C operator + (C x){return C(r+x.r,i+x.i);}
    	C operator - (C x){return C(r-x.r,i-x.i);}
    	C operator * (C x){return C(r*x.r-i*x.i,r*x.i+i*x.r);}
    	void operator = (double x){r=x,i=0;}
    }w[N],x1[N],x2[N],y1[N],y2[N],z[N];
    int L1,L2,a[N],b[N];
    LL res[N];
    char s1[N],s2[N];
    void FFT(C a[]){
    	for (int i=0;i<n;i++)
    		if (i<R[i])
    			swap(a[i],a[R[i]]);
    	for (int t=n>>1,d=1;d<n;d<<=1,t>>=1)
    		for (int i=0;i<n;i+=(d<<1))
    			for (int j=0,prod=0;j<d;j++,prod+=t){
    				C tmp=w[prod]*a[i+j+d];
    				a[i+j+d]=a[i+j]-tmp;
    				a[i+j]=a[i+j]+tmp;
    			}
    }
    int ans[N],acnt=0;
    int main(){
    	scanf("%d%d%s%s",&L2,&L1,s2,s1);
    	for (int i=0;i<L2/2;i++)
    		swap(s2[i],s2[L2-i-1]);
    	for (int i=0;i<L1;i++)
    		a[i]=s1[i]=='*'?0:(s1[i]-'a'+1);
    	for (int i=0;i<L2;i++)
    		b[i]=s2[i]=='*'?0:(s2[i]-'a'+1);
    	for (n=1,L=0;n<L1+L2;n<<=1,L++);
    	for (int i=0;i<n;i++){
    		R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    		w[i]=C(cos(2*i*PI/n),sin(2*i*PI/n));
    	}
    	memset(res,0,sizeof res);
    	for (int i=0;i<n;i++){
    		x1[i]=1.0*a[i]*a[i]*a[i],y1[i]=1.0*b[i];
    		x2[i]=1.0*a[i]*a[i],y2[i]=1.0*b[i]*b[i];
    	}
    	FFT(x1),FFT(x2),FFT(y1),FFT(y2);
    	for (int i=0;i<n;i++){
    		z[i]=x1[i]*y1[i]-C(2.0,0)*x2[i]*y2[i];
    		x1[i]=1.0*a[i],y1[i]=1.0*b[i]*b[i]*b[i];
    	}
    	FFT(x1),FFT(y1);
    	for (int i=0;i<n;i++){
    		z[i]=z[i]+x1[i]*y1[i];
    		w[i].i*=-1.0;
    	}
    	FFT(z);
    	for (int i=0;i<n;i++)
    		res[i]=(LL)(z[i].r/n+0.5);
    	for (int i=L2-1;i<L1;i++)
    		if (res[i]==0)
    			ans[++acnt]=i-L2+2;
    	printf("%d
    ",acnt);
    	for (int i=1;i<=acnt;i++)
    		printf("%d ",ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    MyEclipse快捷键大全
    mac下配置android环境变量
    JAVA NIO 简单介绍
    android读取大图片并缓存
    Android  <meta-data>
    iPhone 6/6 Plus国行版开卖当日抢购攻略
    A380上11万一张的机票什么享受?来看看
    连载15年!《火影忍者》终于迎来大结局
    Windows 技术预览版
    纪录片《天安门》
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4259.html
Copyright © 2011-2022 走看看