题目大意
有一个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[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;
}