七彩线段

链接:https://www.nowcoder.com/acm/contest/212/C
来源:牛客网
 

题目描述

听说彩虹有七种颜色?
一维坐标轴上n条线段,每条线段左端点l,右端点r,颜色为c,从中选m种颜色的互不接触的线段,每种颜色可选多条,所选线段的总长度最长为多少?

输入描述:

第一行2个整数 n, m;
接下来n行,每行3个整数l, r, c。

输出描述:

一个整数,表示所选线段的最长的总长度;若选不了,输出-1;

示例1

输入

复制

4 2
1 3 1
4 5 1
5 8 2
7 9 3

输出

复制

5

示例2

输入

复制

4 3
1 3 1
4 5 1
5 8 2
7 9 3

输出

复制

-1

备注:

1 <= n <= 100000; 1 <= m <= 7;
1 <= l < r <= 1000000000; 1 <= c <= 7;

dp操作

#include<bits/stdc++.h>
#include<stdlib.h>
using namespace std;

typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=b-1;i>=a;--i)
#define lowbit(x) (x&(-x))
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)

const LL INF=1e18;
const int N=100010;

struct Seg {
    LL l,r;
    int c;
    Seg(LL _l=0,LL _r=0,int _c=0)
    {
        l=_l,r=_r,c=_c;
    }
    bool operator<(const Seg& b)const
    {
        if(r==b.r)return l<b.l;
        return r<b.r;
    }
} p[N];


int has[2*N];

unordered_map<int,int> pos;

LL dp[4*N][130];
int num[10];
LL ans=-1;
int n,m;

int vec[10],vis[10];

int cnt;
void solve()
{
    int tmp=0;
    for(int i=0; i<m; i++)tmp=tmp|(1<<(vec[i]-1));
    ans=max(ans,dp[cnt-1][tmp]);
}

void dfs(int tot,int pos)
{
    if(tot==m) {
        solve();
        return;
    }
    if(pos>7)return;//!!!越界应该 在后面,不是在最前面,否则会出现漏掉情况的可能
    dfs(tot,pos+1);//不存在,需要单独列出来
    if(num[pos]) {
        vec[tot]=pos;
        vis[pos]=1;
        dfs(tot+1,pos+1);
        vis[pos]=0;
    }
}

int main()
{
    // freopen("123.txt","r",stdin);
    //freopen("789.txt","w",stdout);
    while(scanf("%d %d",&n,&m)==2) {
        ans=-1;
        pos.clear();
        for(int i=1; i<=n; i++) {
            int l,r,c;
            scanf("%d %d %d",&l,&r,&c);
            num[c]++;
            p[i]=Seg(l,r,c);
            has[(i-1)*2]=l,has[(i-1)*2+1]=r;
        }
        sort(p+1,p+n+1);
        //rep(i,1,n+1)printf("i:%d %lld %lld\n",i,p[i].l,p[i].r);
        has[2*n]=0;
        sort(has,has+2*n+1);
        cnt=unique(has,has+2*n+1)-has;
        for(int i=0; i<cnt; i++)pos[has[i]]=i;
        //rep(j,0,cnt)printf("j:%d %d\n",j,has[j]);
        int t=1<<7;
        for(int i=0; i<=cnt; i++)for(int j=0; j<=t; j++)dp[i][j]=-INF;
        //for(int j=0;j<=t;j++)dp[0][j]=0;
        dp[0][0]=0;
        int id=1;
        for(int i=1; i<cnt; i++) {
            while(id<=n&&p[id].r<=has[i]) {
                for(int j=0; j<t; j++) {
                    if(dp[pos[p[id].l]-1][j]==-INF)continue;
                    int dif=p[id].c-1;
                    int t=j|(1<<dif);
                    dp[i][t]=max(dp[i][t],dp[pos[p[id].l]-1][j]+(p[id].r-p[id].l));
                    //printf("i:%d j:%d t:%d dp[i][t]:%lld\n",i,j,t,dp[i][t]);
                }
                //printf("i:%d id:%d \n",i,id);
                id++;
            }
            for(int j=0; j<t; j++) {
                dp[i][j]=max(dp[i][j],dp[i-1][j]);
            }
        }
        dfs(0,1);
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值