插入屏障就是将一个区间分割成两个区间[1,x]和[x+1,n],所以我们可以利用栈来求出前缀的对数和、后缀的对数和,然后在一个for循环来寻找最大值,减少的最大防守力就是[1,n] - [1,x] - [x+1,n],最优的屏障放置位置就是当前的x+1。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define N 200000
int t,n,ans,pos,sum;
int v1[N],v2[N],a[N];
stack<int>st;
int main(void){
scanf("%d",&t);
for(int k = 1;k <=t;k++){
cin>>n;
v1[0] = v2[n+1] = ans = pos = 0;
for(int i = 1;i <=n;i++)
scanf("%d",&a[i]);
while(st.size())
st.pop();
for(int i = 1;i <=n;i++){
v1[i] = v1[i-1];
sum = 0;
while(!st.empty()&&st.top()<a[i]){
sum++;
st.pop();
}
if(!st.empty())
v1[i] +=sum+1;
else
v1[i] +=sum;
st.push(a[i]);
}
while(!st.empty())
st.pop();
for(int i = n;i>=1;i--){
v2[i] = v2[i+1];
sum = 0;
while(!st.empty()&&st.top()<a[i]){
sum++;
st.pop();
}
if(!st.empty())
v2[i] +=sum+1;
else
v2[i] +=sum;
st.push(a[i]);
}
for(int i = 1;i<=n;i++){
if(v1[n]-v1[i]-v2[i+1]>ans){
ans = v1[n] - v1[i] -v2[i+1];
pos = i + 1;
}
}
printf("Case #%d: %d %d\n",k,pos,ans);
}
return 0;
}