zoukankan      html  css  js  c++  java
  • [CF1313D] Happy New Year

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

    Solution

    首先将所有区间离散化成左闭右开区间,考虑状压 dp,为每个区间分配编号,编号的分配范围是 (0 o 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];
    }
    
    
    
  • 相关阅读:
    PythonStudy——socket 网络编程
    PythonStudy——异常处理
    PythonStudy——subprocess 模块
    PythonStudy——xlrd 与 xlwt 表格处理模块
    MySQLStudy——安装与环境部署
    Redo与undo在开发中的使用
    SQL语句的执行计划(oracle表的三种链接方式)
    SQLSERVER的兼容级别
    查看用户的SQL执行历史
    Spark是一种分布式的计算方案
  • 原文地址:https://www.cnblogs.com/mollnn/p/12468248.html
Copyright © 2011-2022 走看看