二分专项练习(二)

文章提供了三个使用二分查找策略解决的编程竞赛题目。第一题涉及计算砍龙所需的最小持续时间;第二题是关于任务分配和工人的工作效率问题;第三题是寻找在限制条件下最大化朋友收到的礼物价值的问题。每个问题都通过二分查找来确定最优解。
摘要由CSDN通过智能技术生成

习题一:

题目传送门:

https://codeforces.com/contest/1613/problem/C

题意:

有一条血量为k的龙,有n次砍他的机会,a[i]表示第i次从a[i]时刻砍他一刀,从此时刻到a[i+1]-1时刻会对产生1血量的伤害,求砍死龙所需每次最小持续时间是多少。

题解:

二分,假设最小持续时间是x,判断每次看龙持续时间之和(sum+=min(a[i+1]-a[i],x))是否大于等于k,是则返回true,不是则返回false。

代码显示如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
int n, m, h;
typedef pair<int, int> PII;
int a[N];
vector<int>up, dn;
bool check(int x) {
	
	int sum=0;
	for(int i=1;i<n;i++)
	{
		sum+=min(x,a[i+1]-a[i]);
	}
	sum+=x;//别忘记最后还有一段时间要加上
	if(sum>=m) return true;
	else return false;

}

void solve() {
	cin >> n >> m;
	for(int i=1;i<=n;i++) cin>>a[i];
	
	int l=1,r=1e18;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;

}
signed main() {
	int t = 1;
	cin >> t;
	while (t--) {
		solve();
	}
}

习题二:

题目传送门:

https://codeforces.com/contest/1701/problem/C

题意:

现在有𝑚个任务和𝑛个工人,擅长第𝑖个任务的人是𝑎𝑖。存在擅长该任务的人做该任务花费时间为1小时,不擅长该任务的人做该任务需要花费2个小时,每个时刻一个人只能做一个任务,工人可以并行工作,问最少花费多少时间可以把任务做完。

题解:

二分+贪心

擅长做该任务的人做相应任务花费的时间最少,所以我们要尽可能让擅长做该任务的人做该任务,假定最少花费时间是mid,记录下每个师傅要做多少擅长的任务,如果做完他们的时间小于mid(可以多做额外的不擅长的任务extra=(mid-cnt[i])/2(因为做不擅长的任务要花费2小时,做不擅长的任务所需要的时间是1小时,(mid-cnt[i])是在该时间内完成擅长任务的个数,所以在该时间内做不擅长任务的个数是擅长任务的1/2),则就去帮助其他师傅做任务(其他师傅是指做完他们擅长的任务的时间超出mid,需要其他师傅帮他做need=mid-cnt[i]),在这个mid的时间内,如果extra>=need,则合法,否则则不合法。

代码显示如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int n, m, h;
int a[N],cnt[N];
bool check(int mid) {

	int need=0,extra=0;
	for(int i=1;i<=n;i++)
	{
		if(cnt[i]<=mid) extra+=(mid-cnt[i])/2;
		else need+=(cnt[i]-mid);
	}
	if(extra>=need) return true;
	else return false;

}

void solve() {
	memset(cnt,0,sizeof cnt);//别忘记
	cin >> n >> m;
	for(int i=1;i<=m;i++) cin>>h,cnt[h]++;

	int l=1,r=1e9;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;

}
signed main() {
	int t = 1;
	cin >> t;
	while (t--) {
		solve();
	}
}

习题三:

题目传送门:

https://codeforces.com/contest/1619/problem/D

题意:

有 n 个朋友和 m 个商店,每一个商店都有和所有朋友一一对应的 n 个礼物,每一个礼物都有一个对应的价值,因此构成了一个m×n 矩阵。

你可以在任意一家商店中购买任意数量的礼物,但是每个朋友必须收到一份礼物,并且每个朋友只能收一份礼物。

你的目标是让所有朋友收到的礼物中价值的最小值最大,即 ans=min{a1,a2……an−1 ,an } ,求 ans 可能达到的最大值。问在最多去 n − 1家店的情况下,ans 的最大值为多少?
 

题解:

给n个人买礼物,只能再至多n-1家店里买,那么必须会在其中一家店里买至少2个礼物,假设ans的最大值是mid,那么我们check函数就要check两点,第一点是是不是有一家店里开心度大于等于mid的礼物至少有两件,第二点就是否所有人都买到礼物了,遍历每家店,用cnt表示这家店的开心度大于等于mid的个数,如果有,就标记f[x]=1,证明第x个人买到合法的礼物了。

代码显示如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
int n, m, h;
typedef pair<int, int> PII;

vector<int>a[N + 10];
bool check(int mid) {

	vector<bool>f(N+10);
	bool st = false;
	for (int i = 1; i <= m; i++) {
		int cnt = 0;
		for (int j = 1; j <= n; j++) {
			if (a[i][j] >= mid) {
				cnt++;
				f[j]=true;
			}
			
		}
		if (cnt >= 2) st = true;
	}
	if (!st) return false;
	for (int i = 1; i <= n; i++) {
		if (!f[i]) return false;
	}
	return true;

}

void solve() {
	cin >> m >> n;
	for (int i = 1; i <= m; i++) {
		a[i].clear();
		a[i].push_back(0);
		for (int j = 1; j <= n; j++) {
			cin >> h, a[i].push_back(h);
		}
	}
	int l = 0, r = 1e9;
	while (l < r) {
		int mid = (l + r+1) >> 1;
		if (check(mid)) {
			l = mid ;
		} else r = mid - 1;
	}
	cout << l << endl;

}
signed main() {
	int t = 1;
	cin >> t;
	while (t--) {
		solve();
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值