最优屏障
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
const int M = 5 * 1e5 + 10;
int t, n;
int a[M];
int b[M], c[M];
struct node {
int ln, rn;
} p[M];
void call() {
stack<int> s;
for (int i = 0; i < n; ++i) {
int ans = 0;
while (!s.empty()) {
int k = s.top();
if (a[i] > a[k]) {
ans++;
p[k].rn++;
s.pop();
} else {
p[i].ln++;
break;
}
}
p[i].ln += ans;
if (!s.empty()) {
int k = s.top();
p[k].rn++;
}
s.push(i);
}
}
int main() {
cin >> t;
for (int w = 1; w <= t; ++w) {
memset(p, 0, sizeof(p));
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d", &a[i]);
call();//求每座山可以和左边右边山分别连接的数量
b[0] = p[0].ln, c[0] = p[0].rn;
for (int i = 1; i < n; ++i) {//前缀和
b[i] = b[i - 1] + p[i].ln;
c[i] = c[i - 1] + p[i].rn;
}
int ans = 0, minn = 0, g = 0;
for (int i = 1; i < n; ++i) {
ans = c[i - 1] - b[i - 1];//求屏障之后的损失
if (ans > minn) {
minn = ans;
g = i;
}
}
printf("Case #%d: %d %d\n", w, g + 1, minn);
}
return 0;
}
题解:用call函数去求出每座山可以和左边山连接的数量,以及可以和右边山连接的数量;然后两个都做一个前缀和;之后用一个O(n)去枚举屏障的每个位置,用前缀和就可以求出做了屏障之后损失的连接,简单做个比较记录序号就可以得出结果了。