列表

详情


NC21788. Taeyeon的困惑

描述

今天,YPC正在热舞之中,嘴里唱着BJLY的神曲,沉浸在了自己的世界里。 然而Taeyeon又突然抽了一下,问YPC一个问题: 在一个长度为n的区间中,子区间[1,m],[2,m+1],[3,m+2],...,[n-m+1,n]中每个区间前K小之和的和是多少。

其中一个区间的前k小之和指的是将这个区间内的所有数从小到大排序后求出最前面的k个数之和

由于YPC热舞的起劲,无法自拔,于是这个问题只能你来回答。

输入描述

第一行三个整数:n,m,K,意思如题 第二行n个正整数:a[i],意思如题

输出描述

输出仅一行,每个区间前K小的数之和的和。

示例1

输入:

6 3 2
2 3 1 4 5 6

输出:

21

说明:

对于30%数据:1≤n,m≤1000,0≤k≤m≤n,0≤a[i]≤105,m接近于n/2
对于100%数据:1≤n,m≤105,0≤k≤m≤n,0≤a[i]≤105,m接近于n/2。
保证数据纯随机

示例2

输入:

6 3 2
2 2 2 2 2 2

输出:

16

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 77ms, 内存消耗: 4460K, 提交时间: 2019-05-28 16:26:36

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<bits/stdc++.h>
#define N 400010
#define maxn 100000
#define lson k<<1
#define rson k<<1|1
using namespace std;
int sum[N],n,m,k,a[maxn+10];
long long prosum[N],ans;

 void add(int x,int d,int l=0,int r=maxn,int k=1)
{
    sum[k]+=d;
    prosum[k]+=x*d;
    if(l==r)
        return;
    int mid=l+r>>1;
    if(x<=mid)
        add(x,d,l,mid,lson);
    else
        add(x,d,mid+1,r,rson);
    return;
}
 void kth(int p,int l=0,int r=maxn,int k=1)
{
    if(l==r)
    {
        ans+=(long long)l*p;
        return;
    }
    int s=sum[lson],mid=l+r>>1;
    if(s>=p)
    {
        kth(p,l,mid,lson);
        return;
    }
    ans+=prosum[lson];
    kth(p-s,mid+1,r,rson);
    return;
}
int main()
{
    cin>>n>>m>>k;
    for(register int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        add(a[i],1);
        if(i>=m)
        {
            if(i>m)
            add(a[i-m],-1);
        kth(k);
        }
    }
    printf("%lld",ans);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 40ms, 内存消耗: 1252K, 提交时间: 2020-03-16 21:37:21

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=100005;
typedef long long LL;
int n,m,K,Now,Num,a[MAXN],hsh[MAXN];
LL Ans,Sum;
int main()
{
	cin>>n>>m>>K;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<m;i++) hsh[a[i]]++;hsh[a[0]]++;Now=0,Num=hsh[a[0]];
	for(int i=m;i<=n;i++)
	{
		hsh[a[i-m]]--,hsh[a[i]]++;
		Num+=(a[i-m]>Now?0:-1)+(a[i]>Now?0:1);
		if(a[i-m]<=Now) Sum-=a[i-m];
		if(a[i]<=Now) Sum+=a[i];
		while(Num-hsh[Now]>K) Num-=hsh[Now],Sum-=(LL)hsh[Now]*Now,Now--;
		while(Num<K) Num+=hsh[++Now],Sum+=(LL)hsh[Now]*Now;
		Ans+=Sum-((LL)Num-K)*Now;
	}
	printf("%lld\n",Ans);
	return 0;
}

上一题