Kanade’s sum
遍历数组元素,找到元素x可以当第k大的数的合法区间。向x前或后遍历找到离x最近的k-1个比x大的数记下离x的距离num。这就是一个合法区间。再向x后或前(区别于前面的向x前或后)遍历找比x小的数,计算合法区间。将每个x对应的合法区间个数(即x被取了几遍)与x相乘,相加,即是答案。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long LL;
const LL mod = 1e9+7;
int a[N], b[N], pos[N];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, k;
scanf("%d %d", &n, &k);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);//输入
LL ans=0;
for(int i=1; i<=n; i++)
{
int x=a[i], cnt=0, j, sum=0;
b[++cnt]=i;
///找k-1个最接近x的比x大的数
for(j=i+1; j<=n&&cnt<k; j++)
if(a[j]>x) b[++cnt]=j;
///正好找到
if(cnt==k)
{
int num=1;
///向前找
for(; j<=n; j++)
{
if(a[j]<x) num++;
else break;
}
sum+=num;//x在sum个区间内是第k大数
for(j=i-1; j>=1&&cnt>=1; j--)
{
if(a[j]<x) sum+=num;//向后找 比x小的数
else
{
if(cnt==1) break;
num=b[cnt]-b[cnt-1];//记下距离
cnt--;
sum+=num;
}
}
}
///不正好先向前找
else
{
for(j=i-1; j>=1&&cnt<k; j--)if(a[j]>x) b[++cnt]=j;
if(cnt==k)
{
sort(b+1,b+cnt+1);
int num=n-b[cnt]+1;
sum+=num;
for(; j>=1&&b[cnt]>=i; j--)
{
if(a[j]<x)
{
sum+=num;
}
else
{
if(b[cnt]==i) break;
num=abs(b[cnt]-b[cnt-1]);
cnt--;
sum+=num;
}
}
}
}
//printf("%d %d %d\n\n",i, sum, x);
ans+=(LL)x*sum;
}
printf("%lld\n",ans);
}
return 0;
}