URAL 1996 Cipher Message 3

题目

神题。

记得当初DYF和HZA讲过一个FFT+KMP的题目,一直觉得很神,从来没去做。

没有真正理解FFT的卷积。

首先考虑暴力。

只考虑前7位 KMP 找出所有 B 串可以匹配 A 串的位置。

设 a(i) = A(i) & 1, b(i) = B(i) & 1

然后相当于求所有的

c(i) =  ∑k=0m-1 a(i+k) * b(k)

考虑卷积形式:

c(i) =  ∑k=0m-1 a(k) * b(i - k)

将b串反过来

c(i) = ∑k=0m-1  a(k) * b(m-i+k)

改变 c 的定义令原先的 C(i) = 现在的 c(i+m)

得到 C(i) = ∑k=0m-1  a(k) * b(k-i)

所以 C(i) = ∑k=0m  a(k) * b(i-k+n)

然后FFT解决。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <complex>
#include <cmath>

#define N 250010
#define Ex complex<double>
#define pi 3.14159265354

using namespace std;

int n,m,a[N],b[N],same[N],rev[N<<2];

inline void scan(int &x){
    char tmp[11];
    scanf("%s",tmp);
    x=0;
    int len=strlen(tmp);
    for(int i=len-1;~i;i--)
        if(tmp[i]=='1') x|=(1<<(len-i-1));
}

inline bool simple(int a,int b){
    return (a|1)==(b|1);
}

int f[N];
bool match[N];
Ex A[N<<2],B[N<<2],C[N<<2];

void fft(Ex x[],int n,int t){
    for(int i=0;i<n;i++){
        if(rev[i]>i) swap(x[rev[i]],x[i]);
    }
    for(int m=1;m<n;m<<=1){
        Ex wn(cos(pi/m*t),sin(pi/m*t));
        for(int k=0;k<n;k+=(m<<1)){
            Ex wt(1,0);
            for(int i=0;i<m;i++,wt*=wn){
                Ex &A=x[i+m+k],&B=x[i+k],tmp=wt*A;
                A=B-tmp; B=B+tmp;
            }
        }
    }
    if(t==-1){
        for(int i=0;i<n;i++)
            x[i]/=(double)n;
    }
}

int main(){
    freopen("message10.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scan(a[i]);
    for(int i=0;i<m;i++) scan(b[i]);
    f[0]=f[1]=0;
    for(int i=1;i<m;i++){
        int j=f[i];
        while(j&&!simple(b[i],b[j])) j=f[j];
        f[i+1]= simple(b[i],b[j])? j+1:0;
    }
    int j=0;
    bool flag=0;
    for(int i=0;i<n;i++){
        while(j&&!simple(b[j],a[i])) j=f[j];
        if(simple(b[j],a[i])) j++;
        if(j==m) match[i-m+1]=1,flag=1;
    }
    if(!flag){
        puts("No");
        return 0;
    }
    puts("Yes");
    int T=0,nt;
    for(nt=1;nt<=(n+m);nt<<=1) T++;
    for(int i=0;i<nt;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(T-1));
    for(int i=0;i<n;i++) A[i]=a[i]&1;
    for(int i=0;i<m;i++) B[i]=b[m-i-1]&1;
    fft(A,nt,1);
    fft(B,nt,1);
    for(int i=0;i<nt;i++) C[i]=A[i]*B[i];
    fft(C,nt,-1);
    for(int i=0;i<n;i++) same[i]+=(int)(C[i].real()+0.5);
    for(int i=0;i<nt;i++) A[i]=B[i]=C[i]=0;
    for(int i=0;i<n;i++) A[i]=(a[i]&1)^1;
    for(int i=0;i<m;i++) B[i]=(b[m-i-1]&1)^1;
    fft(A,nt,1);
    fft(B,nt,1);
    for(int i=0;i<nt;i++) C[i]=A[i]*B[i];
    fft(C,nt,-1);
    for(int i=0;i<n;i++) same[i]+=(int)(C[i].real()+0.5);
    int ansv=0x3f3f3f3f,anst=0;
    for(int i=0;i<n;i++){
        if(!match[i]) continue;
        if(m-same[i+m-1]<ansv){
            ansv=m-same[i+m-1];
            anst=i+1;
        }
    }
    printf("%d %d\n",ansv,anst);
    return 0;
}
View Code

 

posted @ 2015-06-03 18:07  lawyer'  阅读(165)  评论(0编辑  收藏  举报