二分总结

几年几个月没打二分感觉都不会打了。

擦护栏

题目描述

Jzyz的所有学生获得了一个大扫除的机会——去大街擦护栏。 Jz市大街被分成了M段,每段的长度不一定相同。Jzyz一共有N名学生参加劳动,这些学生将分成M组来完成这项工作,因为长度不同,分配的任务量肯定不同,现在,负责这次大扫除的老师想知道,擦护栏长度最多的同学最少必须擦多长的护栏,这样才能保证尽可能的公平。当然,可以有学生当拉拉队,不用擦护栏,但是每段护栏必须要擦干净。 比如:有5名学生,2段护栏,第一段长度为7,第二段长度为4.可以让3个人负责擦长度为7的,2个人负责长度为4的,那么擦第一段的某个人必须要擦长度为3 的护栏,而其他的人擦长度为2 的护栏。这样就有1位同学必须擦长度为3的护栏。

输入格式

第一行:两个整数N和M(1 ≤ N ≤ 10^9) (1 ≤ M ≤ 300 000, M ≤ N)

接下来M行,每行一个整数,表示每段护栏的长度,保证护栏的长度在[1,10^9] 之间。

输出格式

一个整数,如题目描述,任务量最重的同学擦护栏长度的最小值。

样例数据

input

7 5
7
1
7
4
4

output

4
一道典型的二分答案,二分擦护栏长度的最小值,计算如果全部同学都使用这个值擦护栏,能不能擦完。
#include <bits/stdc++.h>
using namespace std;
int k,n,m,a[1000000],r,l=1,mid;
bool cheak(int k)
 {
 	int cs=0;
    for (int i=1;i<=m;i++)
     if (a[i]%k==0)
      cs+=a[i]/k;
     else
      cs+=a[i]/k+1;//计算第i个护栏需要多少同学擦
    return (cs<=n);//如果擦的同学小于等于同学数,则往大查询
 }
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	 {
	  scanf("%d",&a[i]);
	  if (a[i]>r)r=a[i];
}
    while (l+1<r)
     {
     	mid=(l+r)/2;
     	if (cheak(mid))//判断是否满足条件
     	 r=mid;//向左边找
     	else
     	 l=mid;//向右边找
     }
    if (cheak(r))printf("%d",r);
     else printf("%d",l);
	return 0;
}
P192 A-B Problem

这道题用STL中的lower_bound和upper_bound更方便。
#include <bits/stdc++.h>
using namespace std;
int k,n,m,a[1000000],x,c,ans=0,i;
int main()
{
	scanf("%d%d",&n,&c);
	for (i=1;i<=n;i++) 
	 scanf("%d",&a[i]);
	sort(a+1,a+n+1);//给a数组从小到大排序
	for (i=1;i<=n;i++)
	 ans+=upper_bound(a+1,a+n+1,a[i]-c)-lower_bound(a+1,a+n+1,a[i]-c);//在1-n的范围内查找a[i]-c(B),upper_bound表示比B大的值的下标,lower表示第一个大
于等于B的下标,两者相减为B的数量
	printf("%d",ans);
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值