https://www.luogu.com.cn/problem/P4574
就是数位 dp,用 (f(now,i,j,k,CF)) 表示第 (now) 位,(a,b,c) 的一的个数分别用了 (i,j,k) 个,(CF) 表示有没有进位
然后注意这里应该用顺推,而不是那种记忆化搜索的形式,通过样例就能知道如果写成记忆化搜索,某一个 (f) 的值可能被并不是最优的一个 (c) 来更新了,又因为是记忆化,所以就把这个值当成了最终结果,出现错误
好像还有一种更妙的构造方式,但并不会
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN puts("")
inline long long read(){
register long long x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define INF 0x3f3f3f3f3f3f3f3f
long long f[33][33][33][33][2];
int numa,numb,numc,nummax;
inline void min(long long &a,long long b){(a>b)&&(a=b);}
int main(){
long long a=read(),b=read(),c=read();
int tot=0;
while(a) numa+=(a&1),a>>=1,tot++;
nummax=tot;tot=0;
while(b) numb+=(b&1),b>>=1,tot++;
nummax=std::max(nummax,tot);tot=0;
while(c) numc+=(c&1),c>>=1,tot++;
nummax=std::max(nummax,tot);
std::memset(f,0x3f,sizeof f);
f[0][0][0][0][0]=0;
for(reg int now=0;now<nummax;now++){
for(reg int i=0;i<=numa;i++)for(reg int j=0;j<=numb;j++)for(reg int k=0;k<=numc;k++){
if(f[now][i][j][k][0]!=INF){
min(f[now+1][i][j][k][0],f[now][i][j][k][0]);
if(i<numa&&k<numc) min(f[now+1][i+1][j][k+1][0],f[now][i][j][k][0]+(1<<now));
if(j<numb&&k<numc) min(f[now+1][i][j+1][k+1][0],f[now][i][j][k][0]+(1<<now));
if(i<numa&&j<numb) min(f[now+1][i+1][j+1][k][1],f[now][i][j][k][0]);
}
if(f[now][i][j][k][1]!=INF){
if(k<numc) min(f[now+1][i][j][k+1][0],f[now][i][j][k][1]+(1<<now));
if(i<numa) min(f[now+1][i+1][j][k][1],f[now][i][j][k][1]);
if(j<numb) min(f[now+1][i][j+1][k][1],f[now][i][j][k][1]);
if(i<numa&&j<numb&&k<numc) min(f[now+1][i+1][j+1][k+1][1],f[now][i][j][k][1]+(1<<now));
}
}
}
printf("%lld",f[nummax][numa][numb][numc][0]==INF?-1:f[nummax][numa][numb][numc][0]);
return 0;
}