[CQOI2013]二进制a+b

题意

给定三个整数 a,b,c ,把它们写成无前导 0 的二进制整数。以位数最多的为基准,其它数在前面添加前导0。将它们的各位进行重排,得到 a,b,c,使a+b=c 。求最小的 c ,无解输出 1

a,b,c230

Time Limits:2000ms
Memory Limits:512000KB

分析

a,b,c 在二进制下最多只有 30 位,我们可以考虑数位 dp
a,b,c 转化成二进制数, na,nb,nc 分别为它们二进制下 1 的个数。设 f[l][i][j][k][p] a+b c 在二进制下从第 l 位一直到第 1 位都相等,用了 ia1jb1kc1 ,此时 a+b 在第 l+1 位的进位为 p(p[0,1]) ,当前 c 的最小值。
那么递推公式也比较好想,每做到一位,枚举状态,看它这位放不放 a 1 b 1 c 1 ,每次转移时保证 a+bc 的该位相等,放 1 时注意下最小值的增量就行了。

代码

#include <cstdio>
#include <cstring>
using namespace std;

const int N = 32;
int n,na,nb,nc,ans;
int a,b,C,c[N];
int tar[N];
int f[N][N][N][N][2];

int max(int a,int b) {
    return a > b ? a : b;
}

void init() {
    scanf("%d%d%d",&a,&b,&C);
    int cur = 0;
    while (C) {
        cur ++;
        if (C & 1) nc ++;
        C >>= 1;
    }
    n = cur,cur = 0;
    while (a) {
        cur ++;
        if (a & 1) na ++;
        a >>= 1;
    }
    n = max(n,cur),cur = 0;
    while (b) {
        cur = 0;
        if (b & 1) nb ++;
        b >>= 1;
    }
    n = max(n,cur);
}

int min(int a,int b) {
    if (a == -1) return b;
    if (b == -1) return a;
    return a < b ? a : b;
}

bool solve() {
    memset(f,255,sizeof(f));
    int Inf = f[0][0][0][0][0];
    f[0][0][0][0][0] = 0;
    for (int l = 0;l < n;l ++) {
        for (int i = 0;i <= na;i ++) {
            for (int j = 0;j <= nb;j ++) {
                for (int k = 0;k <= nc;k ++) {
                    for (int p = 0;p < 2;p ++) if (f[l][i][j][k][p] != -1) {
                        if (p == 0 || p == 1 && k < nc) f[l + 1][i][j][k + p][0] = min(f[l + 1][i][j][k + p][0],f[l][i][j][k][p]);
                        if (!p) {
                            if (i < na && j < nb) f[l + 1][i + 1][j + 1][k][1] = min(f[l + 1][i + 1][j + 1][k][1],f[l][i][j][k][0] + c[l + 1]);
                            if (i < na && k < nc) f[l + 1][i + 1][j][k + 1][0] = min(f[l + 1][i + 1][j][k + 1][0],f[l][i][j][k][0] + c[l]);
                            if (j < nb && k < nc) f[l + 1][i][j + 1][k + 1][0] = min(f[l + 1][i][j + 1][k + 1][0],f[l][i][j][k][0] + c[l]);
                        }
                        else {
                            if (i < na) f[l + 1][i + 1][j][k][1] = min(f[l + 1][i + 1][j][k][1],f[l][i][j][k][1] + c[l]);
                            if (j < nb) f[l + 1][i][j + 1][k][1] = min(f[l + 1][i][j + 1][k][1],f[l][i][j][k][1] + c[l]);
                            if (i < na && j < nb && k < nc) f[l + 1][i + 1][j + 1][k + 1][1] = min(f[l + 1][i + 1][j + 1][k + 1][1],f[l][i][j][k][1] + c[l + 1]);
                        }
                    }
                }
            }
        }
    }
    printf("%d",f[n][na][nb][nc][0]);
}

int main() {
    init();
    c[0] = 1;
    for (int i = 1;i <= n;i ++) c[i] = c[i - 1] * 2;
    ans = -1;
    solve();
}

你可能感兴趣的:([CQOI2013]二进制a+b)