20200713 T2 塔防游戏
题目描述
虽然 \(\text{Tom}\) 每天都会花 \(14\) 小时训练,他还是会抽出半个小时玩耍他最喜欢的塔防游戏。
游戏是在一个一维数轴上进行的。在范围为 \([1, n]\) 上有 \(n\) 个防御塔,初始时他们的等级分别为 \(A_i\)。每座防御塔的攻击力等于他的等级。每座防御塔的攻击范围都是 \(r\),也就是说,第 \(i\) 座防御塔能够攻击所有位置 \(j\) 满足\(|i−j|\leq r\),如果 \(r\) 为 \(0\) 则表示他只能攻击到位置 \(i\)。
定义位置 \(i\) 的真实防御值为攻击能够覆盖到 \(i\) 的防御塔的等级和。塔防系统的有效值是真实防御值最小的位置的真实防御值。
由于游戏还在进行,\(\text{Tom}\) 有 \(k\) 次升级防御塔的机会。每次机会都只能使得一座防御塔的等级增加 \(1\)。一座防御塔能被升级多次。
好胜的 \(\text{Tom}\) 想要知道塔防系统的最大有效值能够是多少
输入格式
第一行输入 \(3\) 个整数 \(n,r,k\) 表示有 \(n\) 个位置,每个防御塔能够攻击的半径为 \(r\),能够升级的次数为 \(k\)。
第二行输入 \(n\) 个数表示原有的 \(A_i\)。
输出格式
一行输出答案。
样例
input1
5 0 6
5 4 3 4 9
output1
5
数据规模和限制
对于全部测试数据, 满足 \(N, R \leq 500000\),\(k \leq 10^{18}\), \(A_i \leq 10^{9}\)
各个测试点的数据规模与及特殊性质如下表
\(测试点\) | \(N\) | \(R\) | \(K\) |
---|---|---|---|
\(1\sim 2\) | \(\leq 10\) | \(\leq 10\) | \(\leq 10\) |
\(3\sim 4\) | \(\leq 1000\) | \(\leq 0\) | \(\leq 10^{18}\) |
\(5\sim 6\) | \(\leq 50000\) | \(\leq 50000\) | \(\leq 10^{18}\) |
\(7 \sim 10\) | \(\leq 500000\) | \(\leq 500000\) | \(\leq 10^{18}\) |
思路
贪心 + 二分答案。先计算出原来每个位置的真实防御值,然后差分一下,考虑二分答案一个 \(mid\),\(check\) 的时候就从前往后扫差分数组如果当前位置 \(i\) 的真实防御值不到 \(mid\) 就考虑给 \(i \ + \ r\) 这个位置升级,这样影响的范围最广为 $i \sim i + r + r $ 因为 \(i\) 前面的都满足 \(mid\) 这样应该是最优的。
Code
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 500010
typedef long long ll;
inline void read(ll &T) {
ll x = 0;
bool f = 0;
char c = getchar();
while(c < '0' || c > '9' ) {
if (c == '-') f = !f;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
T = f ? -x : x;
}
ll n, r, maxx;
ll a[MAXN], b[MAXN];
ll k, cf[MAXN], sum[MAXN];
ll max(ll a, ll b) { return a > b ? a : b; }
ll min(ll a, ll b) { return a < b ? a : b; }
bool check(ll x, ll tot = 0) {
ll now = 0;
for (int i = 1; i <= n; ++i) {
now += cf[i];
if (now < x) {
if (tot + x - now > k) return false;
int stop = min(n + 1, i + r + r + 1);
tot += x - now, cf[stop] -= x - now, now += x - now;
}
}
return tot <= k;
}
int main() {
read(n), read(r), read(k);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
maxx = max(maxx, a[i]);
}
for (int i = 1; i <= n; ++i) {
int ll = max(0, i - r - 1);
int rr = min(n, i + r);
a[i] = sum[rr] - sum[ll];
}
ll l = 0, r = k * 2 + maxx * 3;
while(l <= r) {
ll mid = (l + r) >> 1;
for (int i = 1; i <= n; ++i) {
cf[i] = a[i] - a[i - 1];
}
if (check(mid)) l = mid + 1;
else r = mid - 1;
}
printf("%lld\n", r);
return 0;
}