可以把问题转换成在
20−2n
里选a个数,再在里面选b个数,使他们的和在二进制下有c位且最高位不大于
2n
,使这个和最小
然后可以DP,从
20
开始选,
f[i][j][l][k][0]
表示选了前
i
位,a个数里面选了
后记:这题原来可以构造的,Orz PoPoQQQ
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 35;
int f[maxn][maxn][maxn][maxn][2];
int n,a,b,c;
int an,bn,cn;
void up(int &x,int y){if(y>x)x=y;}
void down(int &x,int y){if(y<x)x=y;}
int main()
{
an=bn=cn=0;
scanf("%d%d%d",&a,&b,&c);
int tmp=0; n=0;
while(a)
{
if(a&1)an++; a>>=1;
tmp++;
} up(n,tmp); tmp=0;
while(b)
{
if(b&1)bn++; b>>=1;
tmp++;
} up(n,tmp); tmp=0;
while(c)
{
if(c&1)cn++; c>>=1;
tmp++;
} up(n,tmp); tmp=0;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
for(int l=0;l<=n;l++)
for(int k=0;k<=n;k++)
f[i][j][l][k][0]=f[i][j][l][k][1]=INT_MAX;
for(int i=0;i<=min(an,1);i++)
{
for(int j=0;j<=min(bn,1);j++)
{
f[0][i][j][i^j][i&j]=i+j;
//printf("0 %d %d %d %d %d\n",i,j,i^j,i&j,i+j);
}
}
for(int i=1;i<n;i++)
{
int ap=min(i,an),bp=min(i,bn);
for(int j=0;j<=ap;j++)
for(int l=0;l<=bp;l++)
{
for(int k=0;k<=cn;k++)
{
if(f[i-1][j][l][k][0]!=INT_MAX)
{
int temp=f[i-1][j][l][k][0];
// 0 0
down(f[i][j][l][k][0],temp);
// 0 1
if(l<bn)
down(f[i][j][l+1][k+1][0],temp+(1<<i));
// 1 0
if(j<an)
down(f[i][j+1][l][k+1][0],temp+(1<<i));
// 1 1
if(j<an&&l<bn)
down(f[i][j+1][l+1][k][1],temp+(1<<i+1));
}
if(f[i-1][j][l][k][1]!=INT_MAX)
{
int temp=f[i-1][j][l][k][1];
//0 0
down(f[i][j][l][k+1][0],temp);
//0 1
if(l<bn)
down(f[i][j][l+1][k][1],temp+(1<<i));
//1 0
if(j<an)
down(f[i][j+1][l][k][1],temp+(1<<i));
//1 1
if(j<an&&l<bn)
down(f[i][j+1][l+1][k+1][1],temp+(1<<i+1));
}
//printf("%d %d %d %d %d %d\n",i,j,l,k,0,f[i][j][l][k][0]);
//printf("%d %d %d %d %d %d\n",i,j,l,k,1,f[i][j][l][k][1]);
}
}
}
int ret=f[n-1][an][bn][cn][0];
if(ret==INT_MAX) printf("-1\n");
else printf("%d\n",ret);
return 0;
}