AcWing4655.重新排序
题目
AcWing4655.重新排序
思路
用两个数组,一个数组\(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;
}
rds_blogs