URAL 1996 Cipher Message 3 FFT KMP

来源:互联网 发布:淘宝内部优惠券采集 编辑:程序博客网 时间:2024/06/02 19:41

首先还是要回到卷积的定义上 C(k)=Σi+j=kaibj
这题这种做法我是看了题解之后才知道的。

如果a是a1a2a3a4 ,B是b1b2b3 ,如果我们做卷积,那么其中C5=a2b3+a3b2+a4b1,这和我们的比较方法相反,所以如果我们把B反过来,那么就能利用卷积完成这个比较。

要利用这个性质,分两步计算。
1. a结尾若是1,b结尾若是0,则ax,bx即做FFT的对应位置权值是1,这样求出的是a为1,b为0的矛盾位数。
2. a结尾若是0,b结尾若是1,则ax,bx即做FFT的对应位置权值是1,这样求出的是a为0,b为1的矛盾位数。

因此这两步做完就能判断矛盾的位数。

最后还要做一个KMP来判断前面七位是否满足。

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cmath>using namespace std;const int MAXN = 524288+1000;const int INF = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);struct cp{    double x,y;    cp() {}    cp(double x,double y):x(x),y(y) {}    inline double real()    {        return x;    }    inline cp operator * (const cp& r) const    {        return cp(x*r.x-y*r.y, x*r.y+y*r.x);    }    inline cp operator - (const cp& r) const    {        return cp(x-r.x,y-r.y);    }    inline cp operator + (const cp& r) const    {        return cp(x+r.x,y+r.y);    }};cp a[MAXN],b[MAXN];int r[MAXN],res[MAXN],ax[MAXN],bx[MAXN],n,m;int s1[MAXN],s2[MAXN];void fft_init(int nm,int k){    for (int i=0; i<nm; i++) r[i]= (r[i>>1]>>1) | ((i&1) << (k-1));}void fft(cp ax[],int nm,int op){    for (int i=0; i<nm; i++) if (i<r[i]) swap(ax[i],ax[r[i]]);    for (int h=2,m=1; h<=nm; h<<=1,m<<=1)    {        cp wn = cp(cos(op*2*pi/h),sin(op*2*pi/h));        for (int i=0; i<nm; i+=h)        {            cp w(1,0);            for (int j=i; j<i+m; j++,w=w*wn)            {                cp t=w*ax[j+m];                ax[j+m] = ax[j]-t;                ax[j] = ax[j]+t;            }        }    }    if (op==-1) for (int i=0; i<nm; i++) ax[i].x /= nm;}void trans(int n,int m,int x,int y){    int nm=1,k=0;    while (nm < 2*n || nm <2*m ) nm<<=1,++k;    for (int i=0; i<n; i++)    {        if ((s1[i]&1) == x)            ax[i] = 1;        else            ax[i] = 0;    }    for (int i=0; i<m; i++)    {        if ((s2[m-i-1]&1) == y)            bx[i] = 1;        else            bx[i] = 0;    }    for (int i=0; i<n; i++) a[i] = cp(ax[i],0);    for (int i=0; i<m; i++) b[i] = cp(bx[i],0);    for (int i=n; i<nm; i++) a[i] = cp(0,0);    for (int i=m; i<nm; i++) b[i] = cp(0,0);    fft_init(nm,k);    fft(a,nm,1);    fft(b,nm,1);    for (int i=0; i<nm; i++) a[i] = a[i] * b[i];    fft(a,nm,-1);    nm = n+m-1;    for (int i=0; i<nm; i++) res[i] += (int)(a[i].real() + 0.5);}int nex[MAXN];void getnext(int m){    int j=0;    for (int i=1;i<m;i++)    {        while (j && s2[i]!=s2[j]) j=nex[j];        if (s2[i]==s2[j]) j++;        nex[i+1]=j;    }}void KMP_Count(int n,int m){    int ans=INF,pos=0;    for (int i=0,j=0;i<n;i++)    {        while(j && s1[i]!=s2[j]) j=nex[j];        if (s1[i] == s2[j])        {            j++;            if(j==m)            {                if (ans > res[i])                {                    ans = res[i];                    pos = i-m+1;                }                j=nex[j];            }        }        else j=nex[j];    }    if (ans == INF)        printf("No\n");    else    {        printf("Yes\n");        printf("%d %d\n",ans,pos+1);    }}int main(){    while (scanf("%d%d",&n,&m)!=EOF)    {        memset(res,0,sizeof res);        for (int i=0; i<n; i++) scanf("%d",&s1[i]);        for (int i=0; i<m; i++) scanf("%d",&s2[i]);        trans(n,m,1,0);        trans(n,m,0,1);        for (int i=0;i<n;i++) s1[i]/=10;        for (int i=0;i<m;i++) s2[i]/=10;        getnext(m);        KMP_Count(n,m);    }    return 0;}
原创粉丝点击