刷题 | [JOI 2022 Final] 自学 (Self Study)

博客围绕JOI高中课程学习问题展开,在M个星期N门课的设定下,比太郎有上课和自学两种行动选择,目标是最大化期末每门课理解程度的最小值。给出题目描述、输入输出格式、样例及提示,题解采用二分答案法寻找可行解。

先粘题目:

题目描述

在 JOI 高中高一的第三个学期的 M 个星期的时间内,有 N 门课,编号为 1 \sim N。每个星期有 N 个课时,第 i 个课时上课程 i 的一节课。

比太郎是一位高一学生。对于 N \times M 个课时中的每一个,他会选择如下行动中的一个:

  • 行动 1:比太郎去上课。如果他去上了课程 i 的一节课,那么他对课程 i 的理解程度会增加 A_i。

  • 行动 2:比太郎不去上课。他转而选择任意一门课,并且自学选中的那门课。如果他选中了课程 i 进行了时长为一课时的自学,那么他对课程 i 的理解程度会增加 B_i。

一开始,对每门课的理解程度都为 0。由于比太郎想要在课后练习算法竞赛,他在非上课时间内不会学习。当第三个学期的所有课时结束后,期末考就会举行。

比太郎不想挂科。所以他想要最大化在期末考时对每门课的理解程度的最小值。

给定学期的长度,课程的数量,以及对理解程度的提升数值,请写一个程序计算在期末考时对每门课的理解程度的最小值的最大可能值。

输入格式

第一行,两个正整数 N, M。

第二行,N 个正整数 A_1, A_2, \ldots, A_N。

第三行,N 个正整数 B_1, B_2, \ldots, B_N。

输出格式

输出一行,一个数,表示在期末考时对每门课的理解程度的最小值的最大可能值。

样例 #1

样例输入 #1

3 3
19 4 5
2 6 2

样例输出 #1

18

样例 #2

样例输入 #2

2 1
9 7
2 6

样例输出 #2

7

样例 #3

样例输入 #3

5 60000
630510219 369411957 874325200 990002527 567203997
438920902 634940661 593780254 315929832 420627496

样例输出 #3

41397427274960

样例 #4

样例输入 #4

4 25
1 2 3 4
1 2 3 4

样例输出 #4

48

提示

【样例解释 #1】

举个例子,如果比太郎按如下方式学习,则他对课程 1, 2, 3 的理解程度将分别为 19, 18, 19。

  • 第一周课程 1 的课:自学课程 2;

  • 第一周课程 2 的课:自学课程 2;

  • 第一周课程 3 的课:去上课程 3 的课;

  • 第二周课程 1 的课:去上课程 1 的课;

  • 第二周课程 2 的课:自学课程 3;

  • 第二周课程 3 的课:去上课程 3 的课;

  • 第三周课程 1 的课:自学课程 3;

  • 第三周课程 2 的课:自学课程 2;

  • 第三周课程 3 的课:去上课程 3 的课。

由于对每门课的最小的理解程度不能大于等于 19,输出 18。

这个样例满足子任务 3, 5 的限制。

【样例解释 #2】

这个样例满足子任务 1, 3, 5 的限制。

【样例解释 #3】

这个样例满足子任务 3, 5 的限制。

【样例解释 #4】

这个样例满足子任务 2, 3, 4, 5 的限制。


【数据范围】

本题采用捆绑测试。

对于 100 \% 的数据,1 \le N \le 3 \times {10}^5,1 \le M \le {10}^9,1 \le A_i, B_i \le {10}^9。

  • 子任务 1(10 分):M = 1。

  • 子任务 2(25 分):N \cdot M \le 3 \times {10}^5,A_i = B_i。

  • 子任务 3(27 分):N \cdot M \le 3 \times {10}^5。

  • 子任务 4(29 分):A_i = B_i。

  • 子任务 5(9 分):无特殊限制。


译自 JOI 2022 Final T2「自習 / Self Study

题解

对所有可能答案使用二分答案,向右二分。check是否满足题目所给条件,若能自学则全部自学,若可以全部上课则全部上课,若不能全部上课,则先上课后自学,最后若总课时数大于n*m则返回false。从答案入手,不断二分答案寻找可行解。

代码

#include <iostream>
#include <cstdio>
#define ll long long
​
using namespace std;
​
struct study{
    ll teach, self;
}a[300010];
​
ll m, n, i, l, r, mid, temp;
__int128 sum;
​
ll  ceil_t(ll target, ll eff)//向上取整
{
    if(target % eff == 0){
        return target / eff;
    }
    return (target / eff) + 1;
}
​
bool check(ll target)
{
    sum = 0;
    for(int i = 1; i <= n; i ++){ //遍历每门课的情况
        if(a[i].teach < a[i].self){ //若可以全部自学,则全部自学
            sum += ceil_t(target, a[i].self);
        }
        else{
            if(m * a[i].teach >= target){ //若可以全部上课则上课
                sum += ceil_t(target, a[i].teach);
            }
            else{ //若不可以全部上课,则先上课后自学
                sum += m;
                sum += ceil_t(target - m * a[i].teach, a[i].self);
            }
        }
    }
    
    if(sum > n * m){ //若上课总课时超过n*m,返回false
        return 0;
    }
    return 1;
}
​
int main()
{
    scanf("%lld%lld", &n, &m);
    for(int i = 1; i <= n; i ++){
        scanf("%lld", &a[i].teach);
    }
    for(int i = 1; i <= n; i ++){
        scanf("%lld", &a[i].self);
    }
    l = 1; r = 1000000000000000010;
    while(l <= r){ //二分答案
        mid = l + (r - l) / 2;
        if(check(mid) == true){
            temp = mid;
            l = mid + 1;
        }
        else r = mid - 1;
    }
    printf("%lld", temp);
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值