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;
    }
    

      

  • 相关阅读:
    pat甲级 1155 Heap Paths (30 分)
    pat甲级 1152 Google Recruitment (20 分)
    蓝桥杯 基础练习 特殊回文数
    蓝桥杯 基础练习 十进制转十六进制
    蓝桥杯 基础练习 十六进制转十进制
    蓝桥杯 基础练习 十六进制转八进制
    51nod 1347 旋转字符串
    蓝桥杯 入门训练 圆的面积
    蓝桥杯 入门训练 Fibonacci数列
    链表相关
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4259.html
Copyright © 2011-2022 走看看