[JOI 2022 Final] 自学 题解

洛谷传送门

1.题意简述:

一个学期有 NNM 节课,每天的第 i 节课可以选择效果 ai 的学习与 bi 的自习。问应如何安排每节课,使所有功课最小值最大?

2.思路:

这道题想直接模拟非常麻烦,但是如果我们能够灵活运用二分算法,这道题就非常简单了。

考虑到数据范围较大,我们可以在 01018 的范围内二分枚举答案,写一个 check 函数判断答案是否成立。

check 函数中,我们不妨枚举范围较小的天数 (1n3e5) ,对于每天的 m 节课,我们采用贪心策略,即当自习效率高于上课效率时,我们优先使用自习。因为每天上课次数只有 m 次,而自习次数是无限的。。。

若上课效率更高,则分两种情况讨论:

  • 1.可以在 m 节课内达到二分枚举的答案,则全部上课;

  • 2.不可以在 m 节课内达到目标,则将 m 个机会全部用上,再将剩下效率通过自习完成。

最后如果通过上述情况实现后仍无法达到目标,则返回 false,若 n 天后仍没有退出,返回 true

3.注意事项:

  • 1.在判断是否达到目标时,我们不必统计课程效率,可以统计达到目标最少所需的课程数,这样统计似乎更加简单。。。

  • 2.注意统计课程数时,因为需要用到除法的向上取整,而c++中的 ceil() 函数精度问题比较大,所以推荐使用不带 double 类型的向上取整函数:

int calc (int x, int y) {
	return x / y + (x % y != 0);
}

4.代码实现:

#include <bits/stdc++.h>
#define int long long

using namespace std;

#define N 300010
#define For(i,j,k) for(int i=j;i<=k;i++)
#define IOS ios::sync_with_stdio(),cin.tie(),cout.tie()

int n, m, a[N], b[N];

int calc (int x, int y) {
	return x / y + (x % y != 0);
}

bool check (int mid) {
	int day = 0;
	For (i, 1, n) {
		if (b[i] > a[i]) day += calc (mid, b[i]);
		else if (a[i] * m >= mid) day += calc (mid, a[i]);
		else day += m + calc (mid - a[i] * m, b[i]);
		if (day > n * m) return false;
	}
	return true;
}

signed main () {
	IOS;
	cin >> n >> m;
	
	For (i, 1, n) cin >> a[i];
	For (i, 1, n) cin >> b[i];
	
	int l = 0, r = LLONG_MAX;
	while (l <= r) {
		int mid = l + r >> 1;
		if (check (mid)) {
			l = mid + 1;
		} else {
			r = mid - 1;
		}
	}
	
	cout << l - 1 << endl;
	return 0;
}
posted @   linbaicheng2022  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示