Description
经过多年的杀戮,秦皇终于统一了中国。为了抵御外来的侵略,他准备在国土边境安置
n
名将军。不幸的是这
Input
第一行有一个整数
n(1≤n≤20000)
。接下来
n
行每行一个整数
Output
4 2 2 1 1
Sample Input
4
Solution
这应该是我做过的最巧妙的题之一了。显然应该考虑二分答案,但问题是怎么
O(n)
check
。正解是用一个巧妙的
dp
来
check
。用
mn[i]
表示编号为
i
的人最少和编号为
mn[i]=max(0,a[i]−(x−a[i−1]−a[1]+mx[i−1]))
这样最后检查一下 mn[n] 是否为 0 <script type="math/tex" id="MathJax-Element-117">0</script> 就可以了。
#include<bits/stdc++.h>
using namespace std;
#define N 300001
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drp(i, a, b) for (int i = a; i >= b; i--)
#define fech(i, x) for (int i = 0; i < x.size(); i++)
#define ll long long
inline int read() {
int x = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x;
}
int n;
ll a[N], mx[N], mn[N];
bool check(int x) {
mx[1] = mn[1] = a[1];
rep(i, 2, n) mx[i] = min(a[i], a[1] - mn[i - 1]), mn[i] = max(0ll, a[i] - (x - a[i - 1] - a[1] + mx[i - 1]));
return !mn[n];
}
int main() {
n = read(); ll l = 0, r, ans; rep(i, 1, n) a[i] = read(), l = max(l, a[i] + a[i - 1]); r = l << 1;
while (l <= r) {
int mid = l + r >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans; return 0;
}