重新排序(差分,贪心,排序不等式)

解题思路
Part 1:贪心
我们可以累计每个 AiAi 的被求和次数 cici。容易贪心得到,被求和次数越多的肯定得放越大的数(可用邻项交换证明)(排序不等式)。

我们可以先统计原来的求和的总和 sumsum,再给 AA 数组和统计求和次数的数组 cc 从小到大排好序,最后依次相乘起来即 ∑i=1naici∑i=1naici 减去原来的总和 sumsum 便是答案。

Part 2:差分
统计求和次数时注意到只有修改操作而没有查询操作,于是可以用差分来维护。

具体地,我们建立一个都为 00 的差分数组 bb,当 l∼rl∼r 这段区间被求和时,就 将 blbl 加上 11,br+1br+1 减去 11 就可以了。然后在求前缀和

注意:原来的总和和最大总和都要用 long long 来存储。

时间复杂度:Θ(nlogn)Θ(nlog⁡n)

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int a[N],b[N];
int n,m;
//差分 既可以构造差分又可以在一段区间上加数
void insert(int l,int r,int c)
{
    b[l]+=c;
    b[r+1]-=c;
}
int main()
{
    scanf("%d ",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);
    while(m--)
    {
        int l,r;scanf("%d%d",&l,&r);
        
        insert(l,r,1);
    }
    //求前缀和,统计a数组中 每个数要加多少次
    for(int i=1;i<=n;i++) b[i]+=b[i-1];
    ll sum1=0,sum2=0;
    //没有移动之前的求和
    for(int i=1;i<=n;i++) sum1+=(ll)a[i]*b[i];
    //要想两数差最大,则让后者最大,让出现次数最多的与数最大的相匹配
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++) sum2+=(ll)a[i]*b[i];
    cout<<sum2-sum1<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值