[CF1313D] Happy New Year - 状压dp

序列长度为 \(m\),初态为 \(0\),你可以从 \(n\) 个操作中选择若干个执行,第 \(i\) 个操作对区间 \([l_i,r_i]\) 中每个位置加上 \(1\),最大化最后是奇数的元素个数。保证如果施加了所有操作,一个元素的最大值不会超过 \(k \leq 8\)

Solution

首先将所有区间离散化成左闭右开区间,考虑状压 dp,为每个区间分配编号,编号的分配范围是 \(0\to k-1\),保证没有重叠即可,这样即可设状态为 \(f[i][j]\) 表示考虑到了第 \(i\) 个位置,在 \([pos_{i-1},pos_i)\) 这段区间内的有效状态是 \(j\),在 \([1,pos_i)\) 这段区间内收获的最大值

转移时,如果这个位置是结束也是开始,那么就可以选择保持或者改变;如果这个位置是结束,那么这个位就归零;如果这个位置是开始,那么决策是否打开。为了方便,我们在第 \(i\) 个位置上做区间 \([pos_{i-1},pos_i)\) 的决策,这样如果 \(popcount(j)\) 是奇数,就算上这一段的贡献,否则不算

没想到一个状压 DP 把我卡死了

#include <bits/stdc++.h>
using namespace std;
#define int long long
map <int,int> mp;
const int N = 200005;
const int M = 256;
int n,m,k,pos[N],f[N][M],l[N],r[N],num[N],isl[9][N],isr[9][N],ind;

struct range {
    int l,r;
    bool operator < (const range &b) {
        return l<b.l;
    }
} R[N];

void sh(int &x,int y) {
    x=max(x,y);
}

signed main() {
    ios::sync_with_stdio(false);
    cin >> m >> n >> k;
    for (int i = 1; i <= m; i++) {
        cin >> l[i] >> r[i];
        r[i]++;
        mp[l[i]]++;
        mp[r[i]]++;
    }
    for (auto i = mp.begin(); i != mp.end(); i++) i->second = ++ind, pos[ind] = i->first;
    for (int i = 1; i <= m; i++) {
        l[i] = mp[l[i]];
        r[i] = mp[r[i]];
        R[i] = { l[i],r[i] };
    }
    sort(R + 1, R + m + 1);
    for (int i = 1; i <= m; i++) {
        l[i] = R[i].l;
        r[i] = R[i].r;
    }
    for (int i = 1; i <= k; i++) {
        int p = 1;
        for (int j = 1; j <= m; j++) {
            if (num[j] == 0 && p <= l[j]) {
                p = r[j];
                num[j] = i;
            }
        }
    }
    for (int i = 1; i <= m; i++) {
        isl[num[i]][l[i]] = 1;
        isr[num[i]][r[i]] = 1;
    }
    memset(f, -0x3f, sizeof f);
    f[0][0] = 0;
    pos[0] = 1; //!
    for (int i = 1; i <= ind; i++) {
        for (int s = 0; s < 1 << k; s++)
            if (__builtin_popcount(s)&1)
                f[i - 1][s] +=  (pos[i] - pos[i - 1]);
        for (int j = 1; j <= k; j++) {
            if (isl[j][i] || isr[j][i]) {
                memset(f[i],-0x3f,sizeof f[i]);
                for (int s = 0; s < 1 << k; s++) {
                    if (isl[j][i] && isr[j][i]) {
                        sh(f[i][s], f[i - 1][s]);
                        sh(f[i][s ^ (1 << (j - 1))], f[i - 1][s]);
                    }
                    if (isl[j][i] && !isr[j][i]) {
                        if(!(s&(1<<(j-1)))) sh(f[i][s], f[i - 1][s]);
                        sh(f[i][s | (1 << (j - 1))], f[i - 1][s]);
                    }
                    if (!isl[j][i] && isr[j][i]) {
                        sh(f[i][s & ~(1 << (j - 1))], f[i - 1][s]);
                    }
                }
                for (int s = 0; s < 1 << k; s++) f[i - 1][s] = f[i][s];
            }
        }
    }
    cout << f[ind][0];
}

[CF1313D] Happy New Year - 状压dp

上一篇:LeetCode OJ:Scramble String


下一篇:iLBC 技术点