URAL 1996 Cipher Message 3 FFT KMP

首先还是要回到卷积的定义上 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;
}

猜你喜欢

转载自blog.csdn.net/z631681297/article/details/78137535
FFT