二分答案-整型二分-P2440 木材加工

P2440木材加工

题目描述

木材厂有 n n n 根原木,现在想把这些木头切割成 k k k 段长度 l l l 的小段木头(木头有可能有剩余)。

当然,我们希望得到的小段木头越长越好,请求出 l l l 的最大值。

木头长度的单位是 cm \text{cm} cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

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

##输入格式

第一行是两个正整数 n , k n,k n,k,分别表示原木的数量,需要得到的小段的数量。

接下来 n n n 行,每行一个正整数 L i L_i Li,表示一根原木的长度。

#输出格式

仅一行,即 l l l 的最大值。

如果连 1cm \text{1cm} 1cm 长的小段都切不出来,输出 0

#样例

#样例输入

3 7
232
124
456

#样例输出

114

#提示

#数据规模与约定

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105 1 ≤ k ≤ 1 0 8 1\le k\le 10^8 1k108 1 ≤ L i ≤ 1 0 8 ( i ∈ [ 1 , n ] ) 1\le L_i\le 10^8(i\in[1,n]) 1Li108(i[1,n])

题意

至少分成k段,最大长度是多少

思路

  • 长度最短为0,最长为题目a[i]的最大值。如果从最长开始遍历,然后遍历n个数据。二重循环显然超时。
  • 考虑到结果是一段数据里面选,那么可以考虑让二分结果,节约时间(分的段越多,长度越小,满足二分的线性条件)

数据约束

无约束 ,注意数组长度就行

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int a[N],n,k;
bool check(int t);//判断该值是否符合条件 
    int main()
    {
    	int ans=0,m=-1;//m存储所有木材的里面的最大值,即最大分发 
		cin>>n>>k;
		for(int i=0;i<n;i++) {
			cin>>a[i];
			if(m<a[i] ) m = a[i];
		}
		//开始二分结果 
		int l=1,r= m;
		while(l<=r){ //不能是l<r 一个也让进 !!! 
			int mid = (l+r)/2; //ans = (l+r)>>1;
			if(check(mid)){
				ans = mid; //暂时定一个结果 
				l = mid + 1;//缩小范围 
			}else{
				r = mid-1;
			} 
		}
		cout<<ans;
        return 0;
    }
    bool check(int t){
    	int sum=0;//判断是否有k段
		for(int i=0;i<n;i++){
			sum += a[i]/t;
		} 
		return sum>=k;
	} 

二分的知识点

二分的基本用途是在单调序列或单调函数中做查找操作。因此当问题的答案具有单调性时,就可以通过二分把求解转化
为判定(根据复杂度理论,可知判定的难度小于求解),这使得二分的应用范围变得很广泛。进一步
地,我们还可以通过三分法解决单调函数的极值以及相关问题。

条件:线性条件(越,,,越,,, )/单调性

代码框架

整型代码框架

int L=1,R=n,ans;
while(L<=R)
{
    int mid=(L+R)>>1;
    if(check(mid))ans=mid,L=mid十l; //若满足要求,记下答案,并根据题意缩减范围
    else R=mid-1;
}
    return ans

实型代码框架

double l,r;// jd=0.01(根据题目要求决定精度)
double mid;
while(fabs(l-r)>jd){
    mid=(l+r)/2.0;
    if(check(mid))r=mid;//不能直接+1
    else l=mid;
}
return l;

1.二分答案

最小值最大(或是最大值最小)问题,确定答案后,配合贪心、DP等其他算法检验这个答案是否合理,将最优化问题转换为判定性问题

例如: 将长度为n的序列a分成m个等长的段,求所有分法中每个段的最大值是多大?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值