[bzoj5043]密码破译

9 篇文章 0 订阅

题目大意

有一个n个数的数组a和一个非负整数k(a[],k未知),但是你知道数组b,对于任意i满足bi=ai^k。你还知道 ai=m 求可能最小的k,无解输出-1
n≤100000,bi≤ 260

分析

其实这种题都是套路题。
首先可以预处理cnt[i]表示b数组有几个数二进制第i位为1,p[i]表示m的二进制第i位是否为1。然后从高到低逐位确定k。设f[i][j]表示确定到二进制第i位,只考虑从高到低前i位m还有 2ij 没有被减掉。然后对于k取0或1,第二维会分别变成2* j+p[i]-cnt[i],2*j+p[i]-n+cnt[i]。考虑第二维的大小,从二进制第i位到第0位,假设a全填1,它的和就等于 ij=0n2i2j2i=2n2i1 ,所以第二维有用的大小是2n。这足以通过此题

#include <cstdio>
#include <cstring>
#include <algorithm>

#define min(a,b) ((a)<(b)?(a):(b))

using namespace std;

const int N=2e5+5;

typedef long long LL;

int n,cnt[60],M[60],x,y;

const LL Inf=1ll<<60;

LL a[N],f[2][N],m;

int main()
{
    scanf("%d%lld",&n,&m);
    for (int j=0;j<60;j++,m>>=1) M[j]=(m&1);
    for (int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        for (int j=0;j<60;j++,a[i]>>=1) cnt[j]+=(a[i]&1);
    }
    memset(f[0],127,sizeof(f[0]));
    y=1;
    f[0][0]=0;
    LL p=1ll<<59;
    for (int i=59;i>=0;i--,p>>=1,x^=1,y^=1)
    {
        memset(f[y],127,sizeof(f[y]));
        for (int j=0;j<N;j++) if (f[x][j]<Inf)
        {
            int k=j*2+M[i]-cnt[i];
            if (k>=0 && k<N) f[y][k]=min(f[y][k],f[x][j]);
            k=j*2+M[i]-n+cnt[i];
            if (k>=0 && k<N) f[y][k]=min(f[y][k],f[x][j]+p);
        }
    }
    if (f[x][0]>=Inf) printf("-1\n");else printf("%lld\n",f[x][0]);
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值