CF1188D Make Equal

https://www.luogu.com.cn/problem/CF1188D

奇妙DP题

https://www.luogu.com.cn/blog/RUI-R/solution-cf1188d

重点是要知道可以分别考虑每一位,按后几位排序后进位的一定是一个前缀,这样就可以优化状态数

code:


#include<bits/stdc++.h>
#define ll long long
#define N 200050
using namespace std;
ll a[N], S;
int f[63][N], id[N], s[N];
int cmp(int x, int y) {
    return (a[x] & S) > (a[y] & S);
}
int n;
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
    sort(a + 1, a + 1 + n);
    for(int i = 1; i <= n; i ++) a[i] = a[n] - a[i], id[i] = i;

    memset(f, 0x3f, sizeof f);
    f[0][0] = 0;
    for(int j = 0; j <= 60; j ++) {
        S = (1ll << j) - 1;
        sort(id + 1, id + 1 + n, cmp);
        for(int i = 1; i <= n; i ++) {
            int o = (a[id[i]] >> j) & 1;
            s[i] = s[i - 1] + o;
        }
        
        for(int i = 0; i <= n; i ++) {
            int c = (i - s[i]) + (s[n] - s[i]);
            int jw = s[i];
            f[j + 1][jw] = min(f[j + 1][jw], f[j][i] + c);

            c = s[i] + ((n - i) - (s[n] - s[i]));
            jw = s[n] + (i - s[i]);
            f[j + 1][jw] = min(f[j + 1][jw], f[j][i] + c);
        }
    }
    printf("%lld", f[61][0]);
    return 0;
}
posted @ 2021-12-16 20:04  lahlah  阅读(32)  评论(0编辑  收藏  举报