题目
解题思路
首先,一次的打击是一个以中心点位置和高度为关键信息的直角三角形。
观察发现,如果两次打击影响范围相交,则合并更优。如果包含,则删除被包含的打击。
用类似单调栈的维护即可。
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
void read(int &x) {
x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}
const int N = 1e6 + 100;
struct node {
int lc, h;
node() {}
node(int lc, int h) :lc(lc), h(h) {}
}sta[N];
int n, tp;
int sa[N];
void add(node x) {
if (tp == 0) return void(sta[++tp] = x);
if (sta[tp].lc + sta[tp].h >= x.lc + x.h) return;
if (sta[tp].lc - sta[tp].h >= x.lc - x.h) { tp--; add(x); return; }
if (sta[tp].lc + sta[tp].h <= x.lc - x.h) { sta[++tp] = x; return; }
int a = x.lc - sta[tp].lc, b = sta[tp].h, c = x.h;
int t = b + c - a, r = b - t / 2;
tp--;
if (t % 2 == 0) add(node(x.lc - r, c + r));
else add(node(x.lc - r + 1, c + r));
}
int main() {
//freopen("0.txt", "r", stdin);
read(n);
for (int i = 1; i <= n; i++) read(sa[i]);
for (int i = 1; i <= n; i++) if (sa[i]) add(node(i, sa[i]));
long long ans = 0;
while (tp) ans += sta[tp--].h;
printf("%lld\n", ans);
return 0;
}