您的位置:首页 > 其它

[bzoj5043]密码破译

2017-09-23 22:01 267 查看

题目大意

有一个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还有2i∗j没有被减掉。然后对于k取0或1,第二维会分别变成2* j+p[i]-cnt[i],2*j+p[i]-n+cnt[i]。考虑第二维的大小,从二进制第i位到第0位,假设a全填1,它的和就等于∑ij=0n∗2i∗2j2i=2n∗2i−1,所以第二维有用的大小是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
,f[2]
,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: