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;
}
赛时代码加了点注释,码风混乱,大佬轻喷

浙公网安备 33010602011771号