4.训练士兵

# P10387 [蓝桥杯 2024 省 A] 训练士兵

## 题目描述

在蓝桥王国中,有 n 名士兵,这些士兵需要接受一系列特殊的训练,以提升他们的战斗技能。对于第 i名士兵来说,进行一次训练所需的成本为 p_i 枚金币,而要想成为顶尖战士,他至少需要进行 c_i 次训练。  
为了确保训练的高效性,王国推出了一种组团训练的方案。该方案包含每位士兵所需的一次训练,且总共只需支付S 枚金币(组团训练方案可以多次购买,即士兵可以进行多次组团训练)。  
作为训练指挥官,请你计算出最少需要花费多少金币,才能使得所有的士兵都成为顶尖战士?

## 输入格式

输入的第一行包含两个整数n和S,用一个空格分隔,表示士兵的数量和进行一次组团训练所需的金币数。  
接下来的n行,每行包含两个整数p_i 和c_i,用一个空格分隔,表示第i名士兵进行一次训练的金币成本和要成为顶尖战士所需的训练次数。

## 输出格式

输出一行包含一个整数,表示使所有士兵成为顶尖战士所需的最少金币数。

## 输入输出样例 #1

### 输入 #1

```
3 6
5 2
2 4
3 2
```

### 输出 #1

```
16
```

## 说明/提示

花费金币最少的训练方式为:进行2次组团训练,花费2 × 6 = 12$ 枚金币,此时士兵1, 3 已成为顶尖战士;再花费 4枚金币,让士兵2进行两次训练,成为顶尖战士。总花费为12 + 4 = 16。

对于40\%的评测用例,1 ≤ n ≤ 10^3,1 ≤ p_i
, c_i ≤ 10^5,1 ≤ S ≤ 10^7。

对于所有评测用例,1 ≤ n ≤ 10^5,1 ≤ p_i
, c_i ≤ 10^6

,1 ≤ S ≤ 10^{10}。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

ll p[10000000+10], c[10000000+10],cnt[10000000+10];
int main()
{
	ll n,s;
	cin>>n>>s;
	ll sum=0,now=0,ans=0;
	for(int i=0;i<n;i++)
	{
		cin>>p[i]>>c[i];
		now+=p[i]; //每个士兵单独训练一次所需的费用
		sum+=c[i]*p[i];//所有士兵单独训练完所需费用 
		cnt[c[i]]+=p[i]; //训练成c[i]次的人一次训练所需的花费 
	}
	for(int i=1;i<=1000005;i++)  //考虑ci的范围小于1e6   遍历每个士兵
	{
 
		if(now>s) //单独训练士兵大于组团训练 
		{
			ans+=s; 更新当前已经训练士兵的花费
			sum-=now; 更新剩余士兵单独训练所需费用
			now-=cnt[i]; 更新剩余士兵单独训练一次所需费用  
		}else{
			break;
		} 
	}
	cout<<ans+sum;
	return 0;
 } 

 总结思考:

        题目本身不难,在写的时候注意数据的范围要开longlong,数组命名要规范,做的时候犯了一个低级错误,写成count命名数组;

        对样例进行模拟,now=8,sum=24,

                                     cnt[ c[0] ]=cnt[2]=5,

                                     cnt[ c[1] ]=cnt[4]=2,

                                     cnt[ c[2] ]=cnt[2]=5+3=8;

        遍历每个士兵,从轮数1开始遍历,如果单独训练的所有士兵一次的花费要大于组团训练,选择组团训练,开始更新ans记录当前的花费,ans=0+s=6,sum=24-8=12,now=8-0=8;

        第二轮:ans=6+6=12,sum=12-8=4,now=8-8=0;

        这个时候开始跳出循环,ans=12+4=16;

        题目的精妙在于,使用cnt数组来记录训练c[i]次士兵一次训练所需的花费,在更新数据的时候,当有的士兵已经结束训练次数结束的时候,要更新现在剩余所有士兵训练一次所需的花费,即now值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值