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;
}
posted @ 2020-07-13 20:37  yu__xuan  阅读(231)  评论(3编辑  收藏  举报