2021.3.7

1

链接
题目描述
木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头(木头有可能有剩余),需要得到的小段的数目是给定的。当然,我们希望得到的小段木头越长越好,你的任务是计算能够得到的小段木头的最大长度。木头长度的单位是cm。原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

例如有两根原木长度分别为11和21,要求切割成到等长的6段,很明显能切割出来的小段木头长度最长为5.

输入格式
第一行是两个正整数N和K(1 ≤ N ≤ 100000,1 ≤ K ≤ 100000000),N是原木的数目,K是需要得到的小段的数目。

接下来的N行,每行有一个1到100000000之间的正整数,表示一根原木的长度。

输出格式
能够切割得到的小段的最大长度。如果连1cm长的小段都切不出来,输出”0”。

输入输出样例
输入 #1
3 7
232
124
456

输出 #1
114
题目提取:条件1:把N个长度xi的木头切成M个,求出最长长度

思路:
假设最大长度 = MAX;
mid = 1 条件成立;
mid = 2 条件成立;
……
直到mid = MAX 条件不成立时输出,这样可以从1开始遍历搜索;
同时存在另外一种搜索的方式就是二分搜索 因为答案的区间是固定的(1,max(xi));
如果mid = 1;那么可以切成k段 k > M;
如果mid = 2; 那么可以切成k段K > M;

直到k >= M 段

二分答案只需要考虑
答案范围:while(l + 1 < r)
判断函数:bool ok(int x)

#include<iostream>

using namespace std;

const int N = 1e6 + 10;

long long n,k;
long long a[N];

bool ok(int x){
	long long ans = 0;
	for(int i = 0;i < n;i ++){
		ans += a[i]/x;
		if(ans >= k)	return true;
	}
	return false;
}
int main(){
	cin>>n>>k;
	for(int i = 0;i < n;i ++)	cin>>a[i];
	long long l = 0,r = 100000001;
	long long mid;
	while(l + 1 < r){
		mid = r + l >> 1;
		if(ok(mid))	l = mid;
		else r = mid;
	}
	cout<<l;
	return 0;
}

2

链接
题目描述
第 i 个设备每秒消耗ai个单位能量。能量的使用是连续的,也就是说能量不是某时刻突然消耗的,而是匀速消耗。也就是说,对于任意实数 ,在 k 秒内消耗的能量均为k*ai 单位。在开始的时候第 i 个设备里存储着bi个单位能量。
同时 kotori 又有一个可以给任意一个设备充电的充电宝,每秒可以给接通的设备充能p 个单位,充能也是连续的,不再赘述。你可以在任意时间给任意一个设备充能,从一个设备切换到另一个设备的时间忽略不计。
kotori 想把这些设备一起使用,直到其中有设备能量降为 0。所以 kotori 想知道,
在充电器的作用下,她最多能将这些设备一起使用多久。

输入格式
第一行给出两个整数 n,p。
接下来 n 行,每行表示一个设备,给出两个整数,分别是这个设备的ai 和 bi。

输出格式
如果 kotori 可以无限使用这些设备,输出-1。
否则输出 kotori 在其中一个设备能量降为 0 之前最多能使用多久。
设你的答案为 a,标准答案为 b,只有当 a,b 满足 的时候,你能得到本测
试点的满分。

输入输出样例
输入 #1
2 1
2 2
2 1000

输出 #1
2.0000000000

输入 #2
1 100
1 1

输出 #2
-1

输入 #3
3 5
4 3
5 2
6 1

输出 #3
0.5000000000

说明/提示
对于 100%的数据, 1<=n<=100000,1<=p<=100000,1<=ai,bi<=100000。

题目提取
一个设备N个配件每秒消耗ai自身存储bi,现在有一个每秒释放p容量的电池.可以供这个设备工作多久
条件 ∑bi + p >= ∑ai
假设工作 0.0001s 条件成立
假设工作 0.0002s 条件成立

直到搜索到工作时间最长的;
二分答案考虑
答案范围:while(r - l > 1e-6) 精度为小数点后六位
判断函数:bool ok(doubel x) 注意数据类型

#include<iostream>

using namespace std;

const int N = 1e6 + 10;
double a[N],b[N];
double sum,r = 1e10,l = 0,mid;
int n,p;

bool ok(double x){
	double p1 = x*p;
	double s = 0;
	for(int i = 0;i < n;i ++){
		if(a[i] * x > b[i])
			s += a[i]*x - b[i];
	}
	return s <= p1;
}
int main(){
	cin>>n>>p;
	for(int i = 0;i < n;i ++){
		cin>>a[i]>>b[i];
		sum += a[i];
	}
	if(sum <= p){
		cout<<"-1";
		return 0;
	}
	while(r - l > 1e-6){
		mid = (l + r) / 2;
		if(ok(mid))	l = mid;
		else r = mid;
	}
	cout<<l;
	return 0;
}

3

链接
题目描述
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。

输入格式
第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证L≥1 且N≥M≥0。

接下来 N 行,每行一个整数,第 i 行的整数 D_i( 0 < D_i < L), 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出格式
一个整数,即最短跳跃距离的最大值。

输入输出样例
输入 #1
25 5 2
2
11
14
17
21

输出 #1
4

说明/提示
输入输出样例 1 说明:将与起点距离为 2和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。

另:对于 20%的数据,0 ≤ M ≤ N ≤ 10
对于50%50%的数据,0 ≤ M ≤ N ≤ 100

对于 100%100%的数据,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,0000

题目提取:在一组数列中移去M个数使得两点之间最短距离最大化
设最大的最短距离为MAX
条件:当MAX存在需要移去M1个石头  M1 <= M
当最大最短距离为1时 满足条件

答案范围1-x都是合法的,用二分找到最后一个合法的位置x。
ok函数。从起点到终点遍历,如果两个节点之间的距离小于x的话则是不合法的,然后把当前的石头移掉,如果移动的石子少于等于题目给定的m的话则是合法的。如果当前石头没有被移走的话,i++的同时需要把上一个修改为当前石头。

#include<iostream>

using namespace std;

const int N = 1e5 + 10;

int a[N];
int L,n,m;


bool ok(int x){
	int ans = 0,pos = 0;
	for(int i = 1;i <= n;i ++){
		if(a[i] - a[pos] < x){
			ans ++;
			if(ans > m)	return false;
		}
		else{
			pos = i;
		}
	}
	return true;
}
int main(){
	cin>>L>>n>>m;
	for(int i = 1;i <= n;i ++)	cin>>a[i];
	int l = 1,r = L;
	//a[n] = l;
	while(r > l){
		int mid = l + r + 1>> 1;
		if(ok(mid))	l = mid;
		else r = mid - 1;
	}
	cout<<l;
	return 0;
} 

4

链接
存在的疑惑:
1.边界问题 什么时候 r > l 什么时候 r >= l
2.输出问题 是输出l还是r;
3.收缩问题 l = mid 还是 l = mid + 1;r = mid 还是r = mid - 1;
4.mid设置问题 mid = l + r >> 1还是mid = r + l + 1 >> 1;

#include<iostream>

using namespace std;

const int N = 1e6 + 10;

long long n,m;
long long a[N];

bool ok(long long x){
	long long ans = 0;
	for(int i =0;i < n;i ++)
		if(a[i] > x)
			ans += a[i] - x;
	return ans >= m;
}
int main(){
	cin>>n>>m;
	long long l = 0,r;
	for(int i = 0;i < n;i ++){
		cin>>a[i];
		r = max(r,a[i]);
	}

	while(r >= l){
		long long mid = l + r >> 1;
		if(ok(mid))	l = mid + 1;
		else r = mid - 1;
		//cout<<mid<<endl;
	}
	cout<<r;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值