zoukankan      html  css  js  c++  java
  • D. Happy New Year (状压DP + 扫描线)

    题目: 传送门

    题意: 有 n 个区间,一个数最多被 K 个区间 [Li, Ri] 包含让你选一些区间,使得被奇数个区间包含的数最多,输出这个最大值。

       1 <= n <= 100000, 1 <= k <= 8, 1 <= Li <= Ri <= m <= 1e9

    题解:一个数最多可以被 K 个区间包含,那我们对每个区间动态编号,那使用到的编号最多就是 K 个,然后每个编号对应一个二进制位,做状压DP。

         

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int ID[N];
    
    struct note {
        int x, ch, id;
        note(int x, int ch, int id) : x(x), ch(ch), id(id) { }
    };
    bool cmp(note a, note b) { /// 右端点先处理
        return a.x == b.x ? a.ch < b.ch : a.x < b.x;
    }
    vector < note > Q;
    vector < int > odd;
    int dp[N];
    bool vis[N];
    int main() {
        int n, m, k, l, r; scanf("%d %d %d", &n, &m, &k);
        
        rep(i, 1, n) {
            scanf("%d %d", &l, &r);
            Q.pb(note(l, 1, i));
            Q.pb(note(r + 1, -1, i));
        }
        
        sort(Q.begin(), Q.end(), cmp);
        
        rep(i, 0, (1 << k) - 1) {/// 预处理二进制位上奇数个1的数
            dp[i] = -INF;
            int tmp = i;
            int now = 0;
            while(tmp) {
                now += tmp % 2; tmp = tmp / 2;
            }
            if(now & 1) odd.pb(i);
        }
        
        dp[0] = 0;
        int pre = 0;
        
        for(auto i : Q) {
            for(auto v : odd) { 
                if(dp[v] == -INF) continue; 
                dp[v] += i.x - pre; /// 若存在这样的状态就累加起来
            }
            
            pre = i.x; 
    
            if(i.ch > 0) { /// 左端点
                int now = 0;
                while(now < k && vis[now]) now++; /// 对新加区间编号
                vis[now] = 1;
                ID[i.id] = now;
    
                for(int j = 0; j < (1 << k); j++) { /// 新加区间,那对一些包含此区间的状态更新一下
                    if(((j >> now) & 1) == 0) {
                        dp[j ^ (1 << now)] = dp[j];
                    }
                }
            }
            else { /// 右端点
                int now = ID[i.id];
                vis[now] = 0; ID[i.id] = -1;
                for(int j = 0; j <= (1 << k) - 1; j++) { /// 取消这个区间的编号, 然后, 对包含此区间的状态取max
                    if(((j >> now) & 1) == 1) {
                        dp[j ^ (1 << now)] = max(dp[j ^ (1 << now)], dp[j]);
                        dp[j] = -INF;
                    }
                }
            }
        }
        
        printf("%d
    ", dp[0]);
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    实习第五十七天
    武汉第五十六天
    武汉第五十五天
    常用环境配置
    http 基本验证(nginx)
    nginx configuration
    docker run demo
    初识Hadoop
    大数据简介
    HDFS 存放策略
  • 原文地址:https://www.cnblogs.com/Willems/p/12372283.html
Copyright © 2011-2022 走看看