题目描述
给定 n 个整数对(ai, bi) , 每个整数对的价值是(i-1)*ai + (n-i)*bi (下标从1开始, 这里的 ai 、bi 和输入不一定对应),然后问所有整数对的最小价值总和。
输入
输入包含多组测试用例。
对于每组测试用例,首先输入数对的数量n(n<=1e5)
接下来输入n对数对 ai bi (0<=ai,bi<=1e9)
输出
对于每组测试用例,输出这些整数对的最小价值总和。
样例输入
3
3 2
2 4
6 1
样例输出
11
提示
0 * 6 + 2 * 1 + 1 * 3 + 1 * 2 + 2 * 2 + 0 * 4 = 11
题解
给定整数对寻找最小价值和,尝试用公式推导一下排序的依据
假设分析两个元素:
假设:
-
第 i 个位置是数对 (a1,b1)
-
第 i+1 个位置是数对 (a2,b2)
我们看这两对在这个位置上的代价:
不交换时的代价:
(a1,b1) 在第 i 位 → (i − 1) ⋅ a1 + (n − i) ⋅ b1
(a2,b2) 在第 i + 1 位 → i ⋅ a2 + (n − i − 1) ⋅ b2
总贡献(未交换):
V原 = (i − 1) * a1 + (n − i) * b1 + i * a2 + ( n − i − 1 ) * b2
交换后:
(a2,b2) 在第 i 位 → (i − 1) ⋅ a2 + (n − i) ⋅ b2
(a1,b1) 在第 i + 1 位 → i ⋅ a1 + (n − i − 1) ⋅ b1
总贡献(交换后):
V换 = ( i − 1 ) * a2 + ( n − i ) * b2 + i * a1 + (n − i − 1) * b1
比较差值(交换后 - 原始):
令 Δ = V换 − V原 < 0 (说明值得交换,我们利用贪心的思想找到最小价值的某种排序条件)
Δ = (i − 1)(a2 − a1) + i * (a1 − a2) + ( n − i )(b2 − b1) + (n − i − 1)(b1 − b2) < 0
Δ = a1 − a2 + b2 − b1 < 0
a1 - b1 < a2 - b2
如果a1 - b1 < a2 - b2 ,就应该交换它们。交换后(a2-b2)大于后面的(a1-b1)(因为a2-b2>a1-b1)。所以整个序列应该是按照(ai-bi)从大到小排列(降序排列)。
我们直接使用sort函数来排序就好了,用结构体的话需要重写一下排序的条件
结构体
struct point{
int first; //整数对中的a
int second;//整数对中的b
int total; //存储 a - b
};
cmp函数
bool cmp(const point &a, const point&b){ //sort排序的条件,结构体的某一个值从大到小排
return a.total > b.total;
}
这个题数据比较大我们需要开long long 才能过,完整代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct point{
int first;
int second;
int total;
};
bool cmp(const point &a, const point&b){ //sort排序的条件,结构体的某一个值从大到小排
return a.total > b.total;
}
point a[maxn];
int main(){
int n;
while(cin>>n){
long long ans = 0;
for(int i = 1; i <= n; i++){
cin >> a[i].first >> a[i].second;
a[i].total = a[i].first - a[i].second;
}
sort(a+1,a+1+n,cmp);
for(int i = 1; i <= n; i++){
ans += 1LL * (i - 1) * a[i].first + 1LL * (n - i) * a[i].second;
}
cout << ans <<endl;
}
return 0;
}