1610C - Keshi Is Throwing a Party 题解

题目传送门:
Problem - 1610C - Codeforces

设 f[i] 中的 j 表示你所选出的数列的已知最大长度限制,而且是只管右限制的最大长度限制。

比如说第一个数右限制是 4,那么最大长度限制是 5,因为要算上它本身和它右边最多可能的人的个数。

然后如果第二个数是 9,那么最大限制依然是 5。

如果第二个数是 1,那么最大长度限制缩小为 3,因为要算上这两个和它右边最多可能多出来的 1 个人。

f[j] 表示在上述条件下的最大答案。

这样子我们从左往右扫一遍,每次去更新答案,可以发现每次更新的一定是一个区间。以下是原因:

  • f[j] 是单调递减的。
  • j-f[j] 是单调递增的。
  • 当 j-f[j]-1\leq 第 i 个人的右限制 时,这个人的右限制满足加入 f[j] 的条件。
  • f[j]\leq 第 i 个人的左限制 时,这个人的左限制满足加入 f[j] 的条件。

因此只需要二分求出每次刚好满足右限制和左限制的位置,卡出来的是一个区间。f[j] 用树状数组维护。

#include <cstdio>
#include <cstring>
#include <iostream>
#define lowbit(i) (i&-i)
using namespace std;
const int N = 2e5 + 1;

int t, n, a, b, tree[N ], ans, l,  r。

void add(int i, int x){
    i = n - i;
    while(i <= n){
        tree[i] += x;
        i += lowbit(i);
    }
}

int query(int i){
    i = n - i;
    int ret = 0;
    while(i > 0){
        ret += tree[i];
        i -= lowbit(i);
    }
    return ret;
}

int main(){
    scanf("%d", &t);
    while(t--){
        ans = 0;
        memset(tree + 1, 0, sizeof(int) * n);
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d%d", &a, &b);
            int ans1, ans2;
            l = 0, r = n - 1;
            while(l < r){
                ans1 = (l + r + 1) >> 1;
                if(ans1 - query(ans1) <= a) l = ans1;
                else r = ans1 - 1;
            }
            ans1 = l;
            l = 0, r = n;
            while(l < r){
                ans2 = (l + r) >> 1;
                if(query(ans2) <= b) r = ans2;
                else l = ans2 + 1;
            }
            ans2 = l;
            if(ans2 <= ans1){
                add(ans1, 1);
                add(ans2 - 1, -1);
            }
        }
        for(int i = 0; i < n; i++)
            ans = max(ans, min(i + 1, query(i)));
        printf("%d\n", ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常抱歉,我在之前的代码中没有将keshi定义为Teacher类的成员变量,导致编译错误。下面是修改后的代码,已经测试通过: ```c++ #include <iostream> #include <string> using namespace std; class Teacher { public: int fixed_salary; // 固定工资 int subsidy; // 每个课时补贴 int keshi; // 课时数 virtual void salary() = 0; // 纯虚函数 }; class Professor : public Teacher { public: string id; Professor(string id) : id(id) { fixed_salary = 5000; subsidy = 50; } void salary() { int sal = fixed_salary + keshi * subsidy; cout << id << "的工资为:" << sal << endl; } }; class AssociateProfessor : public Teacher { public: string id; AssociateProfessor(string id) : id(id) { fixed_salary = 3000; subsidy = 30; } void salary() { int sal = fixed_salary + keshi * subsidy; cout << id << "的工资为:" << sal << endl; } }; class Lecturer : public Teacher { public: string id; Lecturer(string id) : id(id) { fixed_salary = 2000; subsidy = 20; } void salary() { int sal = fixed_salary + keshi * subsidy; cout << id << "的工资为:" << sal << endl; } }; void test01(Teacher* tea) { tea->salary(); } int main() { Teacher* tea1 = new Professor("001"); tea1->keshi = 80; Teacher* tea2 = new AssociateProfessor("002"); tea2->keshi = 60; Teacher* tea3 = new Lecturer("003"); tea3->keshi = 40; test01(tea1); test01(tea2); test01(tea3); delete tea1; delete tea2; delete tea3; return 0; } ``` 感谢您指出我的错误,希望这次代码能够满足您的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值