题解二进制

Posted kcn999

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解二进制相关的知识,希望对你有一定的参考价值。

题目大意 

  有三个整数$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][Count(A_(2))][Count(B_(2))][Count(C_(2))][0]$($Count(A_(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 Count(int x)

    int cnt = 0;
    while(x)
    
        cnt += x & 1;
        x >>= 1; 
    
    return cnt;


int main()

    cin >> T;
    int len, tmp;
    while(T--) 
    
        cin >> a >> b >> c;
        cnta = Count(a);
        cntb = Count(b);
        cntc = Count(c);
        len = 0;
        tmp = 1;
        while(tmp <= a || tmp <= b || tmp <= c) tmp <<= 1, ++len;
        memset(dp, 0x7f, sizeof dp);
        dp[0][0][0][0][0] = 0;
        for(register int i = 0; i <= len; ++i)
        
            for(register int ca = 0; ca <= i && ca <= cnta; ++ca)
            
                for(register int cb = 0; cb <= i && cb <= cntb; ++cb)
                
                    for(register int cc = 0; cc <= i && cc <= cntc; ++cc)
                    
                        for(register int j = 0; j <= 1; ++j)
                        
                            for(register int ba = 0; ba <= 1; ++ba)
                            
                                for(register int bb = 0; bb <= 1; ++bb)
                                
                                    for(register int bc = 0; bc <= 1; ++bc)
                                    
                                        if((ba + 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)
                                        );
                                    
                                
                            
                        
                            
                    
                
            
        
        if(dp[len][cnta][cntb][cntc][0] < INF) cout << dp[len][cnta][cntb][cntc][0] << "\n";
        else cout << "-1\n"; 
    
    return 0;
 
参考程序

 

以上是关于题解二进制的主要内容,如果未能解决你的问题,请参考以下文章

题解二进制

BJOI2018简要题解

题解Luogu P1582 倒水 二进制

新生训练赛002题解

LeetCode-位运算相关题解

MySQL OCP888题解068-删除旧的二进制日志