PIPIOJ 1253 最小价值和

题目描述

给定 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值