该题的标程是用链表实现的。思路:首先要确定一点,要求每个点的贡献,也就是说,该点成为第k大的区间个数。我们从小往大开始扫每个数的前面k个和后面k个(很明显都是比当前这个数大的),然后,当一个数是第k大的时候,前面有x个比它大的数,那么后面就有k-x-1个比它大的数。(换个方向想,就是将这若干数排序后,第k小)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=510000;
int n,k,a[N],pos[N],T;
LL ans=0;
int pre[N],np[N];
int s[N],s0;
int t[N],t0;
void erase(int x)
{
int pp=pre[x];
int nn=np[x];
if(pre[x])np[pre[x]]=nn;
if(np[x]<=n)pre[np[x]]=pp;
pre[x]=np[x]=0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
pre[i]=np[i]=0;
}
for(int i=1;i<=n;i++)
{
pre[i]=i-1;
np[i]=i+1;
}
ans=0;
for(int i=1;i<=n-k+1;i++)
{
int p=pos[i];
s0=t0=0;
for(int d=p;d && s0<=k+1;d=pre[d])s[++s0]=d;
for(int d=p;d!=n+1 && t0<=k+1;d=np[d])t[++t0]=d;
s[++s0]=0;t[++t0]=n+1;
for(int j=1;j<=s0-1;j++)
{
if(k+1-j<=t0-1 && k+1-j>=1)ans+=(t[k+1-j+1]-t[k+1-j])*1ll*(s[j]-s[j+1])*i;
}
erase(p);
}
printf("%I64d\n",ans);
}
}