Range k-th Maximum Query-2020百度之星复赛

题意

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6840

分析:

最小等价于每个区间找第 (l+1−k) 小,然后使得和最小,和最大基本等价,所以我们考虑最大。最优方案中,假设 (l=8,k=3),那么一定会这么填 (000001110000011100000111...) 从大到小依次给这些位置 (1) 的位置填上数字。证明大概可以考虑如果我们放了前 (a) 大的,使得尽量多第 (k) 大的大于等于这个数的尽量多,那么就等价于放 (a)(1) ,使得不小于 (k)(1) 的区间尽量多。

代码实现上,按段处理,每段长度为 (l),对于每段中末尾长度为 (k)的部分,分别求出每个数的贡献次数。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=1e5+5;
int a[N],n,l,k;
bool cmp(int x,int y)
{
    return x>y;
}
ll solve()
{
    ll ans=0;
    int d=n/l;
    int r=n-d*l;
    for(int i=k;i<d*k;i++)
    {
        int p=n-i+1;
        if(i%k==0) ans+=1LL*(l-k+1)*a[p];
        else ans+=a[p];
    }
    ans+=1LL*(min(r+1,l-k+1))*a[n-d*k+1];
    if(r>l-k)
    {
        for(int i=1;i<=r-(l-k);i++)
            ans+=a[n-k*d-i+1];
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&l,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        ll ans=solve();
        printf("%lld ",ans);//最大值
        k=l-k+1;//第l-k+1小
        sort(a+1,a+1+n,cmp);//按相反的顺序
        ans=solve();
        printf("%lld
",ans);
    }
}

原文地址:https://www.cnblogs.com/1024-xzx/p/13468298.html