zoukankan      html  css  js  c++  java
  • 北京集训TEST16——图片加密(fft+kmp)

    题目:

    Description

          CJB天天要跟妹子聊天,可是他对微信的加密算法表示担心:“微信这种加密算法,早就过时了,我发明的加密算法早已风靡全球,安全性天下第一!”

          CJB是这样加密的:设CJB想加密的信息有 m 个字节。首先,从网上抓来一张 n(nm) 个字节的图片,分析里面的每个字节(byte)。每个字节有8位(bit)二进制数字。他想替换掉某些字节中最低位的二进制数字,使得这张图片中,连续 m 个字节恰为他想加密的信息。这样,图片看起来没什么区别,却包含了意味深长的信息。

          很显然,不是所有的图片都能让CJB加密他那 m 个字节的信息。他想请你帮忙写个程序判断这张图片是否能加密指定的信息。如果可以加密,则CJB要求改变最少的字节数。如果仍有多种解,他希望信息在图片中的位置越前越好。

    Input

          第一行包含两个整数 n,m(1n,m250000) ,表示图片的大小和信息的大小。

          第二行表示图片的内容。

          第三行表示信息的内容。

          所有内容都以二进制字节的形式给出。每个字节有8位,最左边是最高位,最右边为最低位。

    Output

          如果这张图片不能加密这些信息,输出No

          否则第一行输出Yes,第二行输出两个整数:最少修改的字节数,加密信息的起始位置。如果有多组解,要求加密信息的起始位置尽量前。

    Sample Input

    【样例输入1】
    3 2
    11110001 11110001 11110000
    11110000 11110000
    【样例输入2】
    3 1 
    11110000 11110001 11110000
    11110000

    Sample Output

    【样例输出1】
    Yes
    1 2
    【样例输出2】
    Yes
    0 1

    HINT

    【样例解释】

          图片有3个字节,信息有2个字节。

          图片前两个字节可以匹配信息,需要改变两个字节中的最低位。

          图片后两个字节可以匹配信息,只需要改变一个字节(第二个字节)中的最低位,信息在图片中的起始位置为第2个字节。

    【数据范围与约定】

          对于10%的数据, n,m500

          对于40%的数据, n,m5000

          对于70%的数据, n,m105

          对于所有数据, 1n,m2.5×105


    题解:

    本题解法:KMP+FFT。

    首先,先去掉最低位,跑一次KMP,记录所有可以加密为信息的起始位置。

    然后我们只保留最低位,存入a, b数组里。我们很容易发现,从第 i 个字节作为起始位置计算的话,答案为

    j=1ma[i+j] xor b[j]

    我们可以把b反过来,即可变成卷积形式。

    其中,异或可以拆成两个乘法操作相加,即:a xor b=(a!b)+(!ab) ,那么我们做两次FFT就可以解决了~

    心得:

      又一道fft求卷积题····表示做了这么多次fft终于有点感觉了,其实以后做题要是推出了带∑的式子应该快点想到fft的··只要想办法把里面的运算变成相乘的就行了···

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=250005;
    const double pi=acos(-1.0);
    int a[N],b[N],c[N],d[N];
    int n,m;
    int able[N],tot,rev[N];
    int nxt[N],k,xj;
    int ansa[N],ansb[N];
    char s[N];
    struct Complex {
        double r,i;
        Complex (double r=0,double i=0):r(r),i(i) {}
    } A[N],C[N],B[N],D[N];
    Complex operator + (Complex &a,Complex &b) {
        return Complex(a.r+b.r,a.i+b.i);
    }
    Complex operator - (Complex &a,Complex &b) {
        return Complex(a.r-b.r,a.i-b.i);
    }
    Complex operator * (Complex &a,Complex &b) {
        return Complex(a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r);
    }
    Complex operator / (Complex &a,double x) {
        return Complex(a.r/x,a.i/x);
    }
    inline void kmp()
    {
       for (int i=2,j=0;i<=m;++i) {
            while (j && b[i]!=b[j+1]) j=nxt[j];
            nxt[i]=(b[i]==b[j+1]?++j:j);
        }
        for (int i=1,j=0;i<=n;++i) {
            while (j && a[i]!=b[j+1]) j=nxt[j];
            if (a[i]==b[j+1]) ++j;
            if (j==m) able[++tot]=i-m+1,j=nxt[j];
        }
    }
    inline void pre()
    {
      for (k=1,xj=0;k<=(n<<1);k<<=1,++xj);
        for (int i=0;i<k;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(xj-1));
    }
    void fft(Complex a[],int len,int op=1) {
        for (int i=0;i<len;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
        for (int i=2;i<=len;i<<=1) {
            Complex wn(cos(pi/i),sin(pi/i)*op);
            for (int j=0;j<len;j+=i) {
                Complex w(1);
                for (int k=j;k<j+i/2;++k,w=w*wn) {
                    Complex u=a[k],v=a[k+i/2]*w;
                    a[k]=u+v,a[k+i/2]=u-v;
                }
            }
        }
        if (op==-1) {
            for (int i=0;i<len;++i) a[i]=a[i]/len;
        }
    }
    int main()
    {
      //freopen("a.in","r",stdin);
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
      for(int i=1;i<=m;i++)
        scanf("%d",&b[i]);
      for(int i=1;i<=n;i++)
        c[i]=a[i]%10;
      for(int i=1;i<+m;i++)
        d[i]=b[i]%10;
      for(int i=1;i<=n;i++)
        a[i]=a[i]/10;
      for(int i=1;i<=m;i++)
        b[i]=b[i]/10;
      kmp();
      if(!tot)
      {
        cout<<"No"<<endl;
        return 0;
      }
      else
        cout<<"Yes"<<endl;
      pre();
        for (int i=0;i<k;++i) A[i]=B[i]=Complex();
        for (int i=1;i<=n;++i) A[i]=c[i];
        for (int i=1;i<=m;++i) B[i]=!d[m-i+1];
        fft(A,k);
        fft(B,k);
        for (int i=0;i<k;++i) A[i]=A[i]*B[i];
        fft(A,k,-1);
        for (int i=m+1;i<=n+1;++i) ansa[i-m]=(int)(A[i].r+0.5);
         
        for (int i=0;i<k;++i) A[i]=B[i]=Complex();
        for (int i=1;i<=n;++i) A[i]=!c[i];
        for (int i=1;i<=m;++i) B[i]=d[m-i+1];
        fft(A,k);
        fft(B,k);
        for (int i=0;i<k;++i) A[i]=A[i]*B[i];
        fft(A,k,-1);
        for (int i=m+1;i<=n+1;++i) ansb[i-m]=(int)(A[i].r+0.5);   
      
      for(int i=1;i<=n-m+1;i++)
        ansa[i]+=ansb[i];
      
      int anspos,minchange=1e+9;
      for(int i=1;i<=tot;i++)
      {
        if(minchange>ansa[able[i]])
        {
          minchange=ansa[able[i]];
          anspos=able[i];
        }
      }
      cout<<minchange<<" "<<anspos<<endl;
      return 0;
    }

     

     
  • 相关阅读:
    aws-rds for mysql 5.7.34搭建备库
    Redis 未授权访问漏洞利用总结(转)
    mongoexport/mongimport命令详解
    mongodump/mongorestore命令详解
    redis stream类型 常用命令
    system_time_zone参数值由来
    MySQL加密解密函数AES_ENCRYPT AES_DECRYPT
    MySQL开启SSL加密
    MDL锁获取顺序和优先先
    explicit_defaults_for_timestamp 参数说明
  • 原文地址:https://www.cnblogs.com/AseanA/p/6628558.html
Copyright © 2011-2022 走看看