序列(贪心)

序列

题目描述

有一个整数序列,它的每个数各不相同,我们不知道它的长度是多少(即整数个数),但我们知道在某些区间中间至少有多少个整数,用区间( L i , R i , C i L_i,R_i,C_i Li,Ri,Ci)来描述,表示这个整数序列中至少有 C i C_i Ci 个数来自区间 [ L i , R i ] [L_i,R_i] [Li,Ri],给出若干个这样的区间,问这个整数序列的长度最少能为多少?

输入格式

第一行一个整数 N N N,表示区间个数;

接下来 N N N 行,每行三个整数 L i , R i , C i L_i,R_i,C_i Li,Ri,Ci,描述一个区间。

输出格式

仅一个数,表示该整数序列的最小长度。

样例 #1

样例输入 #1

4
4 5 1
6 10 3
7 10 3
5 6 1

样例输出 #1

4

提示

数据范围及约定

对于全部数据, 1 ≤ N ≤ 1000 1\le N \le 1000 1N1000 0 ≤ L i ≤ R i ≤ 1000 0 \le L_i \le R_i \le 1000 0LiRi1000 1 ≤ C i ≤ R i − L i + 1 1 \le C_i \le R_i-L_i+1 1CiRiLi+1

思路

  • 我们通过举例发现,交界处最好放数字在重叠部分,这样就可以使得数最少。
  • 此时我们可以枚举左端点,因为本道题是给定每个区间的限制说用区间( L i , R i , C i L_i,R_i,C_i Li,Ri,Ci)来描述,表示这个整数序列中至少有 C i C_i Ci 个数来自区间 [ L i , R i ] [L_i,R_i] [Li,Ri],因此我们得用 c n t cnt cnt 来记录每个区间是否满足每个区间的限制,然后,我们要统计这个区间已有的数(用一个 bool 类型的数组来标记安排数的地方),判断是否满足这个区间所需的数:满足,则跳至下一个区间;不满足,则继续安排数的人。(为什么呢?因为每个区间的条件都得要满足)。
  • 如果不满足,从后往前找到未有数的位置(后面的位置越容易与另一个区间重合),给他分配空间。每安排下一个数,最终结果加一,这个区间的数加一,直至本区间的数满足要求。

代码

/*
1 2 3 4 5 6 7 8 9 10
      |-|
       1
         |-|
          1 
           |--------|
                3
            |------|
                3
        
最短长度就是 5 6 7 8

贪心策略:尽量在交界地方放元素,保证元素的总个数最少
所以我们对左端点进行排序
*/

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1010;

struct E{
    int x,y,w;
    bool operator<(const E& t)const{
        return x<t.x;
    }
}e[N];
int n;
int ans,cnt;
bool st[N];

int main(){
    cin>>n;
    
    for(int i=1;i<=n;i++){
        cin>>e[i].x>>e[i].y>>e[i].w;
    }
    
    sort(e+1,e+1+n);
    
    for(int i=n;i>=1;i--){
        // cout<<e[i].x<<" "<<e[i].y<<endl;
        cnt=0;//代表现在区间内已经有cnt个数了
        for(int j=e[i].y;j>=e[i].x;j--){//统计之前已有数的个数。
            if(st[j]){
                cnt++;
            }
        }
        
        if(cnt>=e[i].w)continue;//如果已经满足这个区间的约束,那么就不用再加了,开始看下一个区间
        
        for(int j=e[i].x;j<=e[i].y;j++){
            if(!st[j]){
                cnt++;
                ans++;
                st[j]=true;
                if(cnt>=e[i].w)break;
            }
        }
        
    }
    
    cout<<ans;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值