AcWing 4655. 重新排序(差分+前缀和+贪心)

一、题目信息

在这里插入图片描述

二、思路分析

这道题的话,其实只看前一句话,我们应该用的是前缀和算法。但是这道题在此基础上做了改变,我们根据前缀和可以算出排序之前各个区间和的和。

根据题意,我们需要对数组重新排序,使得排序之后区间和的和最大。那么思路很简单,每个区间的和都会使用到这个数组中的元素,区间之间出现交集的话,那么某些元素就会重新使用。所以,我们只需要将出现次数最多的下标位置放我们最大的元素,以此类推。

而这个思路非常像我们之前在贪心章节中所讲解的排队打水问题。

我们假设一个数被用 C i C_i Ci次,元素中的元素是 a i a_i ai。那么此时我们所有的区间和加起来的结果可以写成下面这个式子:

s u m = c 1 ∗ a 1 + c 2 ∗ a 2 + . . . + c i ∗ a i sum=c_1*a_1+c_2*a_2+...+c_i*a_i sum=c1a1+c2a2+...+ciai
这是一个非常经典的,在贪心章节中所讲解的排序不等式

简单的说,这个不等式的结论就是让最大的出现次数去乘最大的元素。

接下来我们就需要统计一下,每个下标出现的次数。我们准备一个空的数组来记录各个元素的使用次数,如果区间是 [ l , r ] [l,r] [l,r]。那么意思就是,这个区间里的元素会用到一次,也就是说把我们空数组的这些位置都+1。

而这个过程需要用到的则是和前缀和相反的差分算法。

三、代码实现

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll a[N],s[N],b[N],ms[N];
void insert(int l,int r,int a)
{
    b[l]+=a,b[r+1]-=a;
}
int main()
{
    int n,m;
    cin>>n;
    ll sum_0=0,sum_1=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",a+i);
        s[i]=s[i-1]+a[i];
    }
    cin>>m;
    for(int i=0;i<m;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        insert(l,r,1);
        sum_0+=s[r]-s[l-1];
    }
    for(int i=1;i<=n;i++)
        b[i]+=b[i-1];
    
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++)
    {
        sum_1+=(ll)a[i]*b[i];
    }
    cout<<sum_1-sum_0<<endl;
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值