Bridging the Gap 2

题源
牛客暑期多校集训

题目

一群n个步行者在晚上到达河岸。他们想乘船过河,而船最初就在他们这边。船一次最多可容纳 R 个步行者,并且至少需要 L (1 < L < R) 个步行者才能
操作。
划船是一项很累人的工作。每次用船运送一群步行者到河对岸时,都
船上步行者的体力必须大于0,出行后每个步行者的体力都会减少1。最初,我
第-个步行者 (1 ≤ i ≤ n) 的耐力值为 hi。
您需要确定是否可以使用船将所有步行者运送到河的另一边。
输入的第一行包含三个整数n,L,R(1≤L<R≤n≤5×105),分别表示步行者的数量,一次使用船的
最小和最大步行者数量。
输入的第二行包含 n 个整数 h1,h2,…,hn (1 ≤ hi ≤ 5 × 105),其中 hi (1 ≤ i≤n) 表示第 i 个步行者的耐力
值。
如果可以用船将所有步行者运送到河的另一边,请在第一行输出“Yes”(不带引号)。否则,在第一行输出“No”(不带引号)。您可以以任何
大小写(小写或大写)输出每个字母。例如,字符串“yes”、“yes”、“Yes”和“YES”都将被视为肯定回复。

题目分析

首先,定义一来回为两趟,从一个岸边划到另一个岸边为一趟。
我发现,每个人最终在河上划过的趟数都是奇数趟。
将这个团队的体力值可以分为两部分,一部分是将每个人的体力值拿出来一个1,是用来真正送自己过河所消耗的体力值,其他的体力值则又分为两部分,浪费掉的(也就是最终没有用到)和贡献掉的(用于往返河岸来送别人上岸了)。

因此我们可以对体力值进行预处理纷纷-1然后/2(此时的/2就是代码中的/2,向下取整了),这样得到的是每一个人能够划船来回几次,贡献几次(R-L)。

	ll  n, l, r ;
	cin >> n >> l >> r;
	vector<ll > arr(n + 10);
	For cin >> arr[i];
	For arr[i] -= 1;
	For arr[i] /= 2;

然后是对于题目所问的东西进行分析,题目问最终能否把所有人渡过河,首先每个人真正渡自己过河的那1个体力值就先不说了, 主要是贡献出来渡其他人过河的,那么我就要看贡献过河的所需要的往返次数k, 进而锁定k 次 L人总共的所需贡献数k*L

ll  k = ceil(1.0 * (n - r) / (r - l));
	//cout<<k<<endl;
	ll sum = k*l;
	//cout<<sum<<endl;

注意,由于每一次L个人都是可以从某一岸人群中任意选择的,因此仔细思考下是可以发现,每一个人的可以贡献的是min(k,(体力-1)/2),
因此我们有

	For {
		sum -= min( k, arr[i]);
		if (sum <= 0) {
			puts("Yes");
			return;
		}
	}
	puts("No");
	

解答

完整代码

#include <bits/stdc++.h>
using namespace std;
using ll  = long long;
#define For for (ll  i = 1; i <= n; i++)
#define rFor for (ll  i = n; i > 0; i--)
#define rep(i, sta, end) for (ll  i = sta; i <= end; i++)
#define rrep(i, end, sta) for (ll  i = end; i >= sta; i--)
#define All (x) for (auto item : x)

inline void solve() {
	ll  n, l, r ;
	cin >> n >> l >> r;
	vector<ll > arr(n + 10);
	For cin >> arr[i];
	For arr[i] -= 1;
	For arr[i] /= 2;
	ll  k = ceil(1.0 * (n - r) / (r - l));
	//cout<<k<<endl;
	ll sum = k*l;
	//cout<<sum<<endl;
	For {
		sum -= min( k, arr[i]);
		if (sum <= 0) {
			puts("Yes");
			return;
		}
	}
	puts("No");
	
}
int32_t main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	ll  num = 1;
	//cin >> num;
	while (num--) {
		//cout<<"the "<<tmp-num<<"th input"<<endl;
		solve();
	}
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值