输入三个整数a, b, c,把它们写成无前导0的二进制整数。比如a=7, b=6, c=9,写成二进制为a=111, b=110, c=1001。接下来以位数最多的为基准,其他整数在前面添加前导0,使得a, b, c拥有相同的位数。比如在刚才的例子中,添加完前导0后为a=0111, b=0110, c=1001。最后,把a, b, c的各位进行重排,得到a’, b’, c’,使得a’+b’=c’。比如在刚才的例子中,可以这样重排:a’=0111, b’=0011, c’=1010。
你的任务是让c’最小。如果无解,输出-1。
a,b,c<=2^30
一开始以为是从高位到低位的贪心,没想到是数位dp
设f[I,j,k,l,0/1]表示前i位a用了j个1、b用了k个1、c用了l个1、下一位有没有进位的最小c值,转移的时候大力转移即可,注意不要漏了三个数都不添的情况
实际上应该不用开LL的,实际上可以不用写得这么冗长
onenote真是太好用辣
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const int INF=0x7fffffff;
LL f[32][32][32][32][2];
int tot1,tot2,tot3;
int a,b,c,len;
int get_len(int x) {
int ret=0;
for (int i=x;i;i/=2) ret++;
return ret;
}
int main(void) {
scanf("%d%d%d",&a,&b,&c);
rep(i,0,30) {
tot1+=(a&(1<0;
tot2+=(b&(1<0;
tot3+=(c&(1<0;
}
len=std:: max(len,get_len(a));
len=std:: max(len,get_len(b));
len=std:: max(len,get_len(c));
rep(i,0,len) rep(j,0,tot1) rep(k,0,tot2) rep(l,0,tot3) f[i][j][k][l][0]=f[i][j][k][l][1]=INF;
f[0][0][0][0][0]=0;
rep(i,0,len-1) {
rep(j,0,tot1) rep(k,0,tot2) rep(l,0,tot3) {
if (f[i][j][k][l][0]!=INF) {
f[i+1][j][k][l][0]=std:: min(f[i+1][j][k][l][0],f[i][j][k][l][0]);
if (j1][j+1][k][l+1][0]=std:: min(f[i][j][k][l][0]+(1<1][j+1][k][l+1][0]);
if (k1][j][k+1][l+1][0]=std:: min(f[i][j][k][l][0]+(1<1][j][k+1][l+1][0]);
if (j1][j+1][k+1][l][1]=std:: min(f[i][j][k][l][0],f[i+1][j+1][k+1][l][1]);
}
if (f[i][j][k][l][1]!=INF) {
if (l1][j][k][l+1][0]=std:: min(f[i][j][k][l][1]+(1<1][j][k][l+1][0]);
if (j1][j+1][k][l][1]=std:: min(f[i][j][k][l][1],f[i+1][j+1][k][l][1]);
if (k1][j][k+1][l][1]=std:: min(f[i][j][k][l][1],f[i+1][j][k+1][l][1]);
if (j1][j+1][k+1][l+1][1]=std:: min(f[i][j][k][l][1]+(1<1][j+1][k+1][l+1][1]);
}
}
}
if (f[len][tot1][tot2][tot3][0]==INF) puts("-1");
else printf("%lld\n", f[len][tot1][tot2][tot3][0]);
return 0;
}
来自 https://www.lydsy.com/JudgeOnline/problem.php?id=3107