• 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
    ",ansv,anst);
        return 0;
    }
    View Code
  • 相关阅读:
    只需 4 步,手把手教你如何实现滤镜功能
    paip.提升用户体验---c++ qt自定义窗体(1)---标题栏的绘制
    socket网络编程的一些基础知识
    图像处理、模式识别、模式分类、机器视觉推荐图书
    数据挖掘、机器学习和模式识别关系与区别
    Qt4_VS10 程序打包发布
    Qt之多线程
    QT中.pro文件的写法
    高斯定理的证明
    《Linear Algebra and Its Applications》-chaper3-行列式-行列式初等变换
  • 原文地址:https://www.cnblogs.com/lawyer/p/4549892.html
Copyright © 2020-2023  润新知