Description
有一天,小a给了小b一些数字,让小b帮忙找到其中最大的数,由于小b是一个程序猿,当然写了一个代码很快的解决了这个问题。
这时,邪恶的小c又出现了,他问小b,假如我只需要知道这些数字中的某个区间的最大值,你还能做嘛?
小b经过七七四十九天的思考,终于完美的解决了这道题目,这次,他想也让小c尝尝苦头,于是他问小c,我现在想知道存在多少不同的区间的最大值大于等于k,你还能做吗?
这次,小c犯了难,他来请教身为程序猿的你。
Hint:一个区间指al,al+1,…,ar这一段的数且l<=r,一个区间的最大值指max{al,al+1,…,ar},两个区间不同当且仅当[l1,r1],[l2,r2]中l1不等于l2或r1不等于r2
题解
这题是一个叫做控制区间的idea。考虑枚举某一个数为某区间的最大值,那么,这个区间的边界就是前后第一个比它的数(先不考虑相等的情况)。这个显然单调栈就可以处理,那么以当前枚举的数为最大值的区间个数就是 (i−L[i])∗(R[i]−i) 。对于两个数相等的情况,只要处理一下,使得默认前面或后面的数更大就可以防止因两数相等而重复计算的问题。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100006
#define LL long long
using namespace std;
inline char nc(){
static char buf[100000],*i=buf,*j=buf;
return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int n,T,top,stack[maxn],L[maxn],R[maxn],a[maxn];
LL sum[maxn];
void push(int x,int p){
while(top&&(a[stack[top]]<a[x]||a[stack[top]]==a[x]&&p))top--;
stack[++top]=x;
}
int main(){
freopen("maximum.in","r",stdin);
freopen("maximum.out","w",stdout);
n=_read();
for(int i=1;i<=n;i++)a[i]=_read();
for(int i=1;i<=n;i++){
push(i,0);
L[i]=stack[top-1]+1;
}
top=0;stack[0]=n+1;
for(int i=n;i>=1;i--){
push(i,1);
sum[a[i]]+=(LL)(i-L[i]+1)*(stack[top-1]-i);
}
for(int i=100000;i>=1;i--)sum[i]+=sum[i+1];
T=_read();
while(T--){
int x=_read();
printf("%lld\n",sum[x]);
}
return 0;
}