洛谷P4343 [SHOI2015]自动刷题机

解题报告

注意到一个性质(当然不注意到一般也能想到): n 越大,能过的题就越少。这是一个单调的性质。

考虑二分这个 n,最大值和最小值分开做都一样的。这里讲最小值。

check 函数很好想,传进去当前二分的 n,然后按题意模拟,获得实际 AC 数,和给定的 AC 数对比一下确定是高了还是低了,然后更新边界即可。

最大值最小值更新边界的区别可以手玩验证。原则是:求最小值就尽量调低,求最大值就尽量调高。

代码实现

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <set>
#include <map>

// 性质:N 越大,能过的题越少 

const int MAXL = 1e5 + 10;

int l; long long int k;
long long int mnans = -1, mxans;
long long int logg[MAXL];

long long int check(long long int fn) {
	long long int exist = 0, acc = 0;
	for (int i = 1; i <= l; ++i) {
		exist = std::max(exist + logg[i], 0ll);
		if (exist >= fn) { ++acc; exist = 0; }
	}
	return acc; // 过题数 
}

int main() {
	scanf("%d %lld", &l, &k); 
	for (int i = 1; i <= l; ++i) scanf("%lld", logg + i);
	long long int l = 1, r = 0x7f7f7f7f7f7f7f7f;
	while (l <= r) { // min
		long long int mid = (l + r) >> 1ll;
		long long int acc = check(mid);
		if (acc <= k) {
			r = mid - 1;
			if (acc == k) mnans = mid; // 满足条件更新答案 
		} else l = mid + 1;
	} if (mnans == -1) {
		puts("-1"); return 0;
	}
	l = 1, r = 0x7f7f7f7f7f7f7f7f;
	while (l <= r) { // max
		long long int mid = (l + r) >> 1ll;
		long long int acc = check(mid);
		if (acc >= k) {
			l = mid + 1;
			if (acc == k) mxans = mid;
		} else r = mid - 1;
	} printf("%lld %lld", mnans, mxans);
	return 0;
}
上一篇:2.计算机组成原理之计算机系统概论


下一篇:<JVM中篇:字节码与类的加载篇>01-Class字节码文件结构