AcWing4655.重新排序

题目

原题链接

参考题解

AcWing4655.重新排序

image

思路

用两个数组,一个数组\(a\)来记录原数组,\(b\)数组来记录每个数字被计算了多少次,题目中给的是$ [l,r] $区间内的数字求和,也就是每次给的 \([l,r]\)区间内的数字都会被计算一次,即\(b[l,r]\)上的数都要+1,不妨用一个差分数组来统计,b[l] ++,b[r+1] --,然后对\(b\)这个差分数组求前缀和,所得的前缀和数组就是所要的记录每个数字被统计了多少次的数组

\(b\)差分数组求一遍前缀和(还是用\(b\)数组存结果),现在得到了两个数组\(a\)\(b\)

两数组一个是原元素数组,一个是某个数字统计的频数数组
让和最大就要尽可能让数值大的元素的频数大,那就让两个数组都sort一遍

计算\(\sum _{i=1}^{n}a_{i}\cdot b_{i}\)就是原始的\(sum\)

\(a\)\(b\)两数组sort得到的结果再计算\(\sum _{i=1}^{n}a_{i}\cdot b_{i}\)就是期望最大和的结果\(ans\)

最后答案就是\(ans - sum\)

一个数字最多被计算1e5次,所以一个数最大是1e5 * 1e6,和最大是1e5 * 1e6 * 1e5,肯定会爆int,开long long存sum、ans

代码

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;
const int N = 1e5+10;

int a[N],b[N];
LL sum,ans;
int n,m;

int main()
{
    cin >> n ;
    for(int i = 1;i <= n;i ++) cin >> a[i];
    
    cin >> m ;
    for(int i = 1;i <= m;i ++)
    {
        int l,r;
        cin >> l >> r ;
        b[l] ++ ,b[r + 1] -- ;
    }
    
    for(int i = 1;i <= n; i ++)
    {
        b[i] = b[i - 1] + b[i] ;
        sum += (LL) a[i]*b[i] ;
    }
    
    sort(a+1,a+n+1),sort(b+1,b+n+1);
    
    for(int i = 1;i <= n;i ++)
    {
        ans += (LL) a[i]*b[i];
    }
    
    cout << ans - sum;
    
    return 0;
}
posted @ 2023-01-05 10:52  r涤生  阅读(17)  评论(0编辑  收藏  举报