CF1856C To Become Max

赛时贪心半天没想出来,用二分过掉了。

我们可以二分 \(k\) 次操作后 \(a\) 的最大值 \(mid\)

二分主要是 check 函数怎么写。

模拟一下样例,或许可以找到规律。如果 \(a_i = x\),则 \(a_{i - 1}\) 最多可以加到 \(x + 1\)。相反,如果想让 \(a_i\) 的值变为 \(x\),那么 \(a_{i + 1} \ge x - 1\)。由于 \(n\) 非常小,所以我们可以 \(O(n^2)\) 枚举。具体地,我们可以枚举 \(i\),计算让 \(a_i\) 变为 \(mid\) 的最小步数。对于每个 \(i\),我们可以利用上面的性质往后枚举,算出 \(a_{i + 1}, a_{i+2},...,a_{n-1}\) 的最小值,再计算步数。由于 \(a_n\) 的值是不可以改动的,所以枚举时有些边界问题需要注意。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 1010;

inline void in(int &x)
{
	x = 0; bool f = 0; char c = getchar();
	while(c < '0' || c > '9')
	{
		if(c == '-') f = 1;
		c = getchar();
	}
	while(c >= '0' && c <= '9')
	{
		x = (x << 3) + (x << 1) + (c & 15);
		c = getchar();
	}
	x = f ? -x : x;
}

inline void out(int x)
{
	if(x < 0) putchar('-'), x = -x;
	if(x / 10) out(x / 10);
	putchar((x % 10) | 48);
}

int t, n, k, maxx;
int a[N];

bool check(long long mid)
{	
	for (int i = 1; i < n; i ++ )
	{
		long long cnt = 0, t = mid;
		for (int j = i; j < n; j ++ )
		{
			if(j == n - 1 && t - (long long)a[j] > 1ll * max(0, a[j + 1] - a[j] + 1)) //a[n-1] 需要加的步数不得大于 a[n-1] 最多能加的步数 
			{
				cnt = 1e18;
				break;
			}
			if(t <= 1ll * a[j]) break;
			cnt += (t - 1ll * a[j]);
			t --;
		}
		if(cnt <= 1ll * k) return 1;
	}
	return 0;
}

int main()
{
	in(t);
	while (t -- )
	{
		in(n); in(k);
		for (int i = 1; i <= n; i ++ ) in(a[i]);
		
		maxx = 0;
		for (int i = 1; i <= n; i ++ ) maxx = max(maxx, a[i]);
		
		long long l = (long long)maxx + 1ll, r = 1e18, mid;
		while (l <= r)
		{
			mid = l + r >> 1ll;
			if(check(mid)) l = mid + 1ll;
			else r = mid - 1ll;
		}
		printf("%lld\n", l - 1ll);
	}
	return 0;
}

赛时代码加了点注释,码风混乱,大佬轻喷

posted @ 2023-08-07 21:26  Shine_Star  阅读(48)  评论(0)    收藏  举报