2021牛客寒假算法基础集训营3 B-内卷 (尺取)

题目链接:点这里~

题目大意

n个同学考试,需要去给每位同学评定等级,一共有五个等级,但是对于每个同学来说,每个等级分别对应五个不同考试分数:ai, bi, ci, di, ei

现在有要求,评定A的同学数量不能超过k,问最终考试成绩最大值和最小值的差值最小是多少?

思路

每个分数对应一个同学id、一个评定等级,把这些n*5个数据按照分数从小到大排序,使用双指针(尺取法)计算答案

需要满足的条件是选的分数能够对应n个同学,评A等级的数量不超过k,所以能不选A就尽量不选。

如果说该区间里面某个同学出现了不止一个分数,其中有一个是评A的分数,那么可以不评A的而是其他的。但是如果说该同学只有一个分数,并且是评A的分数,那么只能评A。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define io cin.tie(0);ios::sync_with_stdio(false);
#define debug(x) cout<<#x<<"="<<x<<endl
#define lowbit(x) x&(-x)
#define pii pair<int,int>
#define mk make_pair
#define ll long long
#define rs p<<1|1
#define ls p<<1
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline ll read(){
    ll p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=(p<<1)+(p<<3)+(c^48),c=getchar();}
    return f*p;
}

struct node{
    int id, score, rank; //编号 分数 等级
    bool operator < (const node &a) const{
        return score < a.score;
    }
}a[maxn];
map<int, int> mp; //区间存同学分数个数
int vis[maxn];    //区间同学是否有评A的
int cnt, n, k;    //cnt评A个数 
void add(int x){  //区间加值
    ++ mp[a[x].id];
    if(a[x].rank){
        if(mp[a[x].id] == 1) cnt ++; //如果该同学只有一个A的分数,那么只能评A
        vis[a[x].id] = 1;
    } else if(mp[a[x].id] == 2 && vis[a[x].id]) cnt --; //如果说有A但是数量刚好是2,说明之前评A,那么现在可以不评A了
}
void del(int x){ //区间去值
    if(a[x].rank){
        if(mp[a[x].id] == 1) cnt --; //只有一个A的分数,那么评A的就要少一个了
        vis[a[x].id] = 0;
    } else if(mp[a[x].id] == 2 && vis[a[x].id]) cnt ++; //如果说有A但是数量刚好是2,说明去掉该分数之后只剩下一个A了,那么下一个要评A了
    if(-- mp[a[x].id] == 0) mp.erase(a[x].id);
}
bool ok(){ //区间标准: n个同学 A不超k
    return mp.size() == n && cnt <= k;
}
void solve(){
    int m = 0;
    cin >> n >> k;
    for(int i = 1; i <= n; i ++){
        int x; cin >> x;
        a[++m] = {i, x, 1};
        for(int j = 1; j < 5; j ++){
            cin >> x;
            a[++m] = {i, x, 0};
        }
    }
    sort(a + 1, a + m + 1);
    int r = 1, ans = inf;
    for(int l = 1; l <= m; l ++){
        if(l - 1) del(l - 1);
        while(!ok() && r <= m) add(r ++);
        if(ok()) ans = min(ans, a[r - 1].score - a[l].score);
    }
    cout << ans << endl;
}
int main(){
    io;
    solve();
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值