CF1291C·Mind Control

初见安~这一场是真的——啊啊啊啊啊啊啊啊本来我C都写出来了结果一直WA6,今天早上了才发现是特判的时候还写错了……【丢人

这里是传送门:Codeforces #616 Div2 C Mind Control

CF1291C·Mind Control_第1张图片Solution

一开始看到可以拿到的最小的最大值,想到的是二分答案,但是对于check函数贪心判断有点迷。所以开始转换问题。【后文中的m都是题目给出的m-1,表示前面有多少个人】题目的意思很重要,因为他说的是你可以控制k个人的选择,但是是在一开始就告知了。什么意思?如果你把控制的k个人放到随机的m-k个人后面,那么在当前最坏的情况下或许你这样安排可以得到答案,但是这种安排放到另一个随机的情况下还能变的更坏。比如样例一的第一组数据,可以手枚看看【我手枚了半个小时,debug了一个小时……好丢人啊】所以我们要控制的k个一定是放在最前面。然后看这个题的数据范围,\small \sum n\leq 3500,是可以用n^2的算法的。所以我们枚举前面k个人的选择,再枚举后面m-k个人的选择。对于选择的枚举,其实因为在左右两端选择过后剩余的一段序列长度都是一样的,所以我们这两部分都枚举中间最后剩的区间的左右端点即可。

然后我就WA2了。因为枚举长度的时候用到了m-k,并且没有特判k>=m的情况。然后我特判了,WA6。因为我在特判的时候枚举的区间长度还是写错了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊阿啊。

听说二分答案确实能写?【我太菜了写不出来了。

上代码——

#include
#include
#include
#include
#include
#include
#define maxn 4000
using namespace std;
typedef long long ll;
int read() {
	int x = 0, f = 1, ch = getchar();
	while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
	while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
	return x * f;
}

int T, n, a[maxn], m, k;
signed main() {
	T = read();
	while(T--) {
		n = read(), m = read() - 1, k = read();
		for(int i = 1; i <= n; i++) a[i] = read();
		if(!m) {printf("%d\n", max(a[1], a[n])); continue;}
		if(k >= m) {
			register int L = n - m, ans = 0;//
			for(int i = L; i <= n; i++) ans = max(ans, max(a[i], a[i - L + 1]));
			printf("%d\n", ans); continue;
		}
		if(!k) {//这里好像可以不用判定
			register int L = n - m, mx = 0x3f3f3f3f;
			for(int i = L; i <= n; i++) mx = min(mx, max(a[i], a[i - L + 1]));
			printf("%d\n", mx); continue;
		}
		register int L = n - k, ans = 0;//L是前k个人拿走后的序列长度,L2同理
		for(int i = L; i <= n; i++) {
			register int l = i - L + 1, r = i, mx = 0x3f3f3f3f, L2 = L - (m - k);
			for(int j = l + L2 - 1; j <= r; j++) mx = min(mx, max(a[j - L2 + 1], a[j]));
			ans = max(ans, mx);//↑是在枚举最优取法,所以看随机情况后的最坏情况谁最优。
		}
		printf("%d\n", ans);
	}
	return 0;
}

后期补上了E的题解,并在这里推荐一个大佬的A~F的题解报告https://www.cnblogs.com/zxytxdy/p/12258265.html

迎评:)
——End——

你可能感兴趣的:(Codeforces)