题解:找出x左右两边大于x的k个数,左边记为cntl右边记为cntr,当cntl+cntr==k时,开始统计有多少个区间以x为第k大值。
重点是从小到大找x,x的情况全部考虑完后,把x从链表里删掉。
复杂度为O(n*k)
#include<iostream>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxn=1e6;
int t,n,k,id[maxn];
struct node{
int nxt,pre,id;
}buf[maxn];
ll ans;
int main(){
scanf("%d",&t);
while(t--){
ans=0;
scanf("%d%d",&n,&k);
for(int x,i=1;i<=n;i++){
scanf("%d",&x);
id[x]=i;
buf[i]=node{i+1,i-1,i};
}
buf[n+1].id=n+1;
for(int i=1;i<=n;i++){
int l=id[i],r=id[i];
int cntl=1,cntr=0;
while(cntl<k){
if(buf[l].pre==0) break;
l=buf[l].pre;
cntl++;
}
while(cntl){
while(cntl+cntr<k){
if(buf[r].nxt==n+1) break;
r=buf[r].nxt;
cntr++;
}
while(cntl+cntr>k){
cntr--;
r=buf[r].pre;
}
if(cntl+cntr==k){
int L=buf[l].id-buf[buf[l].pre].id;
int R=buf[buf[r].nxt].id-buf[r].id;
ans+=(ll)L*R*i;
}
l=buf[l].nxt,cntl--;
}
buf[buf[id[i]].pre].nxt=buf[id[i]].nxt;
buf[buf[id[i]].nxt].pre=buf[id[i]].pre;
}
printf("%lld\n",ans);
}
}