题目大意
有三个整数$A$、$B$、$C$,以下用$N_{2)}$表示$N$的二进制(没有前导$0$)。
设$A_{2)}$、$B_{2)}$、$C_{2)}$的最大长度为$L$($L leqslant 30$),你需要构造三个正整数$X$、$Y$、$Z$,满足以下条件:
(1) $X_{2)}$、$Y_{2)}$、$Z_{2)}$的长度都不超过$L$。
(2) $A_{2)}$与$X_{2)}$中$1$的个数相同。
(3) $B_{2)}$与$Y_{2)}$中$1$的个数相同。
(4) $C_{2)}$与$Z_{2)}$中$1$的个数相同。
(5) $X+Y=Z$。
给你$A$,$B$,$C$,你需要求出最小的满足条件的$Z$。如果不存在满足条件的$Z$,那么输出$-1$。
题解
我们设$dp[i][a][b][c][j]$表示当前$X_{2)}$和$Y_{2)}$的最大长度为$i$,$Z_{2)}$的最大长度为$i + 1$,$X_{2)}$、$Y_{2)}$、$Z_{2)}$中$1$的个数分别为$a$、$b$、$c$,满足$X + Y = Z$的最小的$Z$,且$Z_{2)}$的第$i + 1$位(最高位)为$j$。
对于$dp[i][a][b][c][j]$,我们只需要枚举$X_{2)}$、$Y_{2)}$、$Z_{2)}$的第$i + 1$位分别为什么,就可以更新$dp[i + 1][a’][b’][c’][j’]$的值。最后输出的自然是$dp[L][CountA_{2)})][CountB_{2)})][CountC_{2)})][0]$($CountA_{2)})$表示$A_{2)}$中$1$的个数,其他同)。
#include <iostream> #include <cstring> #define LENGTH 30 + 5) #define INF 0x7f7f7f7f7f7f7f7f using namespace std; int T; int a, b, c; int cnta, cntb, cntc; long long dp[LENGTH][LENGTH][LENGTH][LENGTH][2]; int Countint x) { int cnt = 0; whilex) { cnt += x & 1; x >>= 1; } return cnt; } int main) { cin >> T; int len, tmp; whileT--) { cin >> a >> b >> c; cnta = Counta); cntb = Countb); cntc = Countc); len = 0; tmp = 1; whiletmp <= a || tmp <= b || tmp <= c) tmp <<= 1, ++len; memsetdp, 0x7f, sizeof dp); dp[0][0][0][0][0] = 0; forregister int i = 0; i <= len; ++i) { forregister int ca = 0; ca <= i && ca <= cnta; ++ca) { forregister int cb = 0; cb <= i && cb <= cntb; ++cb) { forregister int cc = 0; cc <= i && cc <= cntc; ++cc) { forregister int j = 0; j <= 1; ++j) { forregister int ba = 0; ba <= 1; ++ba) { forregister int bb = 0; bb <= 1; ++bb) { forregister int bc = 0; bc <= 1; ++bc) { ifba + bb + j & 1) != bc) continue; dp[i + 1][ca + ba][cb + bb][cc + bc][ba + bb + j >> 1] = min dp[i + 1][ca + ba][cb + bb][cc + bc][ba + bb + j >> 1], dp[i][ca][cb][cc][j] + bc << i) ); } } } } } } } } ifdp[len][cnta][cntb][cntc][0] < INF) cout << dp[len][cnta][cntb][cntc][0] << " "; else cout << "-1 "; } return 0; }
参考程序