zoukankan      html  css  js  c++  java
  • bzoj5043: 密码破译

    Description

     小Q发明了一个新的加密算法,对于一个长度为n的非负整数序列a_1,a_2,...,a_n,他会随机选择一个非负整数k,

    将每个数都异或上k得到b_1,b_2,...,b_n,即b_i=a_i xor k。不幸的是,健忘的小Q睡了一觉之后就把密钥k忘得
    一干二净了,不过他隐约记得a_1+a_2+...+a_n的值为m,你能帮他找到一个可行的密钥吗

    Input

    第一行包含两个整数n,m(1<=n<=100000,0<=m<2^{60}),分别表示序列的长度以及加密前所有数的和。
    第二行包含n个整数b_1,b_2,...,b_n(0<=b_i<2^{60}),表示加密后的序列。

    Output

     输出一个非负整数k,若无解输出-1,若有多组解,输出最小的k。

    从高位到低位dp确定k的值,状态表示为当前考虑完第i位,m已被凑出了j,此时k的最小值。观察到$j$是$2^i$的倍数,且当$frac{j}{2^i}$在O(n)范围时才对最终答案有影响,因此总状态数可以接受,在O(nlogm)级别。

    #include<bits/stdc++.h>
    typedef long long i64;
    const int N=2e5+7;
    const i64 inf=1ll<<60;
    char ib[N*30],*ip=ib;
    i64 _(){
        i64 x=0;
        while(*ip<48)++ip;
        while(*ip>47)x=x*10+*ip++-48;
        return x;
    }
    int n,t[65][2];
    i64 m,f[N],g[N];
    void mins(i64&a,i64 b){if(a>b)a=b;}
    int main(){
        fread(ib,1,sizeof(ib),stdin);
        n=_(),m=_();
        for(int i=1;i<=n;++i){
            i64 x=_();
            for(int j=0;j<60;++j)++t[j][x>>j&1];
        }
        n*=2;
        for(int i=1;i<=n;++i)f[i]=inf;
        for(int i=59;i>=0;--i){
            for(int j=m>>i&1;j<=n;j+=2)g[j]=f[j>>1];
            for(int j=0;j<=n;++j)f[j]=inf;
            int c1=t[i][0],c0=t[i][1];
            for(int j=m>>i&1;j<=n;j+=2)if(g[j]<inf){
                if(j>=c0)mins(f[j-c0],g[j]);
                if(j>=c1)mins(f[j-c1],g[j]|1ll<<i);
            }
        }
        printf("%lld
    ",f[0]==inf?-1ll:f[0]);
        return 0;
    }
  • 相关阅读:
    javascript之数组去重方法
    经典问题之爬楼梯
    javascript之事件循环机制
    javascript之闭包
    javascript之动态改变this上下文
    块级元素的垂直居中对齐
    js数组对象
    javascript-冒泡法排序
    javascript-数组
    javascript-循环
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7690427.html
Copyright © 2011-2022 走看看