【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6058
题目意思
给你长度为n的a数组,问你数组a组成的区间第k大的总和。
解题思路
确定a数组一个元素x,判断x右边是否有k比x大的元素,没有左边补。找到右边第k个比x大的数a[j](或小于k),如果a[j]右边还有y个比x小的数,就多y个区间满足第k大。右边找找完往左找,每找到一个比x大数,右边比x的退一个,也就是去掉a[j],到a[j-1]结束,但是要加上a[j]到a[j-1]中比x小的个数。。不断往左找直到k个比x大的都到左边为止
代码部分
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#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;
for(j=i+1; j<=n&&cnt<k; j++) ///先往右找
if(a[j]>x)
b[++cnt]=j; ///记录比a[i]大的数字位子
if(cnt==k) ///当找到k个比a[i]大的数时,也啊a[i]为第k大
{
int num=1;
for(; j<=n; j++) ///继续往右有多少个比a[i]小的数就可以组成多少那个区间
{
if(a[j]<x) num++;
else break;
}
sum+=num;
for(j=i-1; j>=1&&cnt>=1; j--)///开始往左找
{
if(a[j]<x) sum+=num; ///比a[i]小就而外多个区间
else ///如果比a[i]大就把最右边比a[i]大的数去掉
{
if(cnt==1) break;
num=b[cnt]-b[cnt-1]; ///加上最右边和倒二之间比a[i]小的个数
cnt--;
sum+=num;
}
}
}
else ///如果右边没法找到k个比a[i]大的数
{
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; ///加上最右边比a[i]大的数后面比a[i]小的数
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;
}
}
}
}
ans+=(LL)x*sum;
}
printf("%lld\n",ans);
}
return 0;
}