原题链接
在蓝桥王国中,有 n n n 名士兵,这些士兵需要接受一系列特殊的训练,以提升他们的战斗技能。对于第 i i i 名士兵来说,进行一次训练所需的成本为 p i p_i pi 枚金币,而要想成为顶尖战士,他至少需要进行 c i c_i ci 次训练。
为了确保训练的高效性,王国推出了一种组团训练的方案。该方案包含每位士兵所需的一次训练,且总共只需支付 S S S 枚金币(组团训练方案可以多次购买,即士兵可以进行多次组团训练)。
作为训练指挥官,请你计算出最少需要花费多少金币,才能使得所有的士兵都成为顶尖战士?
输入的第一行包含两个整数 n n n 和 $S $,用一个空格分隔,表示士兵的数量和进行一次组团训练所需的金币数。
接下来的 n n n 行,每行包含两个整数 p i p_i pi 和 c i c_i ci,用一个空格分隔,表示第 i i i 名士兵进行一次训练的金币成本和要成为顶尖战士所需的训练次数。
输出一行包含一个整数,表示使所有士兵成为顶尖战士所需的最少金币数。
3 6
5 2
2 4
3 2
16
花费金币最少的训练方式为:进行 2 2 2 次组团训练,花费 2 × 6 = 12 2 × 6 = 12 2×6=12 枚金币,此时士兵 1 , 3 1, 3 1,3 已成为顶尖战士;再花费 4 4 4 枚金币,让士兵 2 2 2 进行两次训练,成为顶尖战士。总花费为 12 + 4 = 16 12 + 4 = 16 12+4=16。
对于 40 % 40\% 40% 的评测用例, 1 ≤ n ≤ 1 0 3 , 1 ≤ p i , c i ≤ 1 0 5 , 1 ≤ S ≤ 1 0 7 1 ≤ n ≤ 10^3,1 ≤ p_i , c_i ≤ 10^5,1 ≤ S ≤ 10^7 1≤n≤103,1≤pi,ci≤105,1≤S≤107。
对于所有评测用例, 1 ≤ n ≤ 1 0 5 , 1 ≤ p i , c i ≤ 1 0 6 , 1 ≤ S ≤ 1 0 10 1 ≤ n ≤ 10^5,1 ≤ p_i , c_i ≤ 10^6,1 ≤ S ≤ 10^{10} 1≤n≤105,1≤pi,ci≤106,1≤S≤1010。
贪心 + 排序
对比每一次全部士兵单独训练和集体训练的费用
在过程中要不断更新全部士兵单独训练的费用
哪个花费更少就采用哪种模式进行训练
排序是为了后续可以更新全部士兵单独训练的费用
#include
using namespace std;
typedef long long ll;
const int N =1e6+10;
struct p{
int cost;
int cnt;
}a[N];
//按照训练次数升序排序
bool cmp(struct p p1, struct p p2){
return p1.cnt<p2.cnt;
}
int main(){
//士兵个数
int n;
//组团训练花费
ll s;
scanf("%d%lld",&n,&s);
//所有士兵训练一次的花费
ll total=0;
for(int i=0; i<n; i++){
int cost,cnt;
scanf("%d%d",&cost,&cnt);
a[i]={cost,cnt};
total+=cost;
}
sort(a,a+n,cmp);
ll ans=0;//统计答案
ll group=0;//统计集体训练次数
for(int i=0; i<n; i++){
//如果所有士兵单独训练一次的花费大于团练一次的花费,那么进行团练
//由于我们对训练次数进行了升序排序
//当前士兵可以团练的次数就等于其训练成为,顶尖战士的训练次数
if(total>=s){
//当前士兵进行团练,累积答案
ans+=(a[i].cnt-group)*s;
//因为当前士兵已经成为顶尖士兵,要更新所有士兵进行一次训练的费用
total-=a[i].cost;
//为了计算后面士兵的训练次数,还需要记录团练的次数
group+=a[i].cnt-group;
}
//所有士兵单独训练一次的花费小于团练一次的花费,那么每个士兵进行单独训练
else{
//同理,每个士兵能进行单独训练的次数等于当前士兵训练成为顶尖战士的训练次数
//由于可能已经累积了group变量的值,这里训练的次数要减去group
ans+=(a[i].cnt-group)*total;
total-=a[i].cost;
group+=a[i].cnt-group;
}
}
printf("%lld",ans);
return 0;
}
import java.util.*;
class Soldier {
int cost;
int cnt;
Soldier(int cost, int cnt) {
this.cost = cost;
this.cnt = cnt;
}
}
class Main {
static final int N = 1000010;
static Soldier[] a = new Soldier[N];
static long totalCost = 0;
// 按照训练次数升序排序
static Comparator<Soldier> cmp = new Comparator<Soldier>() {
@Override
public int compare(Soldier p1, Soldier p2) {
return Integer.compare(p1.cnt, p2.cnt);
}
};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 士兵个数
int n = scanner.nextInt();
// 组团训练花费
long s = scanner.nextLong();
for (int i = 0; i < n; i++) {
int cost = scanner.nextInt();
int cnt = scanner.nextInt();
a[i] = new Soldier(cost, cnt);
totalCost += cost;
}
Arrays.sort(a, 0, n, cmp);
long ans = 0;
int group = 0;
for (int i = 0; i < n; i++) {
// 如果所有士兵单独训练一次的花费大于团练一次的花费,那么进行团练
if (totalCost >= s) {
// 当前士兵进行团练,累积答案
ans += (a[i].cnt - group) * s;
// 因为当前士兵已经成为顶尖士兵,要更新所有士兵进行一次训练的费用
totalCost -= a[i].cost;
// 为了计算后面士兵的训练次数,还需要记录团练的次数
group += a[i].cnt - group;
} else {
// 所有士兵单独训练一次的花费小于团练一次的花费,那么每个士兵进行单独训练
ans += (a[i].cnt - group) * totalCost;
totalCost -= a[i].cost;
group += a[i].cnt - group;
}
}
System.out.println(ans);
scanner.close();
}
}
网上各种答案汇入自己的理解~
编写本篇文章目的是笔者想以输出的形式进行学习,顺便记录学习点滴
如果本篇文章对你有帮助的话那就点个赞吧
本篇文章可能存在多处不足,如有修改意见,可以私信或者评论我哦