给定一个 1∼n 的排列 a1,a2,a3,…,an,想知道所有满足 r−l≥k 的区间 [l,r] 里 的数中第 k 大的元素,输出它们的和。
第一行两个整数 n,k。
接下来一行 n 个整数 a1,a2,a3,…,an。
输出一行,一个整数表示答案。
5 2
1 2 3 4 5
30
其中区间 [1,5],[2,5],[3,5],[4,5] 的第 2 大为 4,区间 [1,4],[2,4],[3,4] 的第 2 大为 3,区间 [1,3],[2,3] 的第 2 大为 2,区间 [1,2] 的第 2 大为 1。
共 10 组数据。 测试点 1,2 满足 1≤n≤100。
测试点 3,4 满足 1≤n≤103。
测试点 5,6 满足 k=1。
测试点 7,8 满足 1≤n≤5×104。
对于 100% 的数据,满足 1≤n≤5×105,1≤k≤50。
#include<bits/stdc++.h>
using namespace std;
int n,k,tl,tr,ll,lr,ps,vp,cnt;
long long ans=0;
int l[500006],r[500006],v[500006];
set<pair<int,int> >st;
int main(){
scanf("%d %d",&n,&k);
for(int i=0;i<=n+1;i++){
if(i>0&&i<=n){
scanf("%d",&v[i]);
st.insert({v[i],i});
}
r[i]=i+1;
l[i]=i-1;
}
for(auto i:st){
vp=i.first;
ps=i.second;
tl=l[ps];
tr=r[ps];
ll=lr=ps;
cnt=1;
while(cnt<k&&ll!=r[0]){
ll=l[ll];
cnt++;
}
while(cnt<k&&lr!=l[n+1]){
lr=r[lr];
cnt++;
}
if(cnt<k)break;
while(ll<=ps&&lr!=l[n+1]){
ans+=1ll*vp*(ll-l[ll])*(r[lr]-lr);
ll=r[ll];
lr=r[lr];
}
r[tl]=tr;
l[tr]=tl;
}
printf("%lld",ans);
return 0;
}