http://codeforces.com/contest/954/problem/G
题目很巧妙的第一个地方在于把弓箭手讷讷感覆盖到的第一个位置 +1,不能覆盖到的位置 -1,后面的加前面的遍历一遍就形成了初始的防御的状态、然后通过二分检查、看看什么状态能符合、
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class G {
static final int MAXN = 500005;
static long[] sum = new long[MAXN]; // 一开始的防御力量
static long[] prepare = new long[MAXN]; // 预备役弓箭手的布置、、
static int N, R;
static long K;
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();
N = (int) in.nval;
in.nextToken();
R = (int) in.nval;
in.nextToken();
K = (long) in.nval;
int tmp;
for (int i = 1; i <= N; i++) {
in.nextToken();
tmp = (int) in.nval; // 输入当前城墙上的位置的弓箭手的数量、、、
sum[Math.max(0, i - R)] += tmp;
if (i + R < N) {
sum[i + R + 1] -= tmp;
}
}
for (int i = 1; i <= N; i++) {
sum[i] += sum[i - 1]; // 遍历形成初始的防御力量分布、
}
long l = 0, r = (long) 2e18, mid, ans = 0;
while (l <= r) {
mid = (l + r) >> 1;
if (check(mid)) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
out.println(ans);
out.flush();
}
private static boolean check(long x) {
long rest = K, need;
long add = 0;
for (int i = 0; i < MAXN; i++) {
prepare[i] = 0;
}
for (int i = 1; i <= N; i++) {
add += prepare[i];
if (sum[i] + add < x) {
need = x - sum[i] - add;
rest -= need;
if (rest < 0) {
return false;
}
prepare[i + 1] += need; // 分配弓箭手防御这一块区域(距离越远防御的效果越好)(下限越高)
if (i + 2 * R < N) {
prepare[i + 2 * R + 1] -= need;
}
}
}
return true;
}
}