牛客 - Wannafly挑战赛26 - C - 七彩线段(DP+离散)

Wannafly挑战赛26 - C - 七彩线段

由于颜色只有七种,线段有100000条,所以可以用DP[i][j]表示最后一个线段的右端点位置 < i,且包含 j 颜色的最大长度,(状态压缩,用七位二进制数表示七种颜色的状态)。

l,r范围较大,但n较小,所以将其进行离散化处理。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, m, Rank[N*2], Rn;
int head[N<<1], nt[N<<1], _id[N<<1], sz;
struct node{
    int l, r, c, len;
    friend bool operator < (node a, node b) {
        return a.r < b.r;
    }
}a[N];
LL dp[N*2][(1<<7)+10];
int get_Rank(int x) {
    return lower_bound(Rank+1, Rank+1+Rn, x) - Rank;
}
int count(int x) {
    int ans = 0;
    while(x) {
        ans += x & 1;
        x >>= 1;
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++) {
        scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].c);
        a[i].len = a[i].r - a[i].l; a[i].c --;
        Rank[++Rn] = a[i].l; Rank[++Rn] = a[i].r;
    }
    sort(Rank+1, Rank+1+Rn);
    Rn = unique(Rank+1, Rank+1+Rn) - Rank - 1;
    sort(a+1, a+1+n);
    for(int i=1;i<=n;i++) {
        int rk = get_Rank(a[i].r);
        nt[++sz] = head[rk], _id[sz] = i, head[rk] = sz;
    }
    for(int i=1;i<=Rn;i++) {
        for(int j=0;j<1<<7;j++) {
            dp[i][j] = max(dp[i][j], dp[i-1][j]);
            for(int k=head[i]; k; k=nt[k]) {
                int to = _id[k];
                int col = (1<<a[to].c) | j;
                int pre = get_Rank(a[to].l)-1;
                if(dp[pre][j] == 0 && j) continue;
                dp[i][col] = max(dp[i][col], dp[pre][j] + a[to].len);
            }
        }
    }
    LL ans = 0;
    for(int i=1;i<1<<7;i++) {
        if(count(i) == m) ans = max(ans, dp[Rn][i]);
    }
    if(ans == 0) ans = -1;
    printf("%lld\n", ans);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值