二分总结

来源:互联网 发布:养匪自重知乎 编辑:程序博客网 时间:2024/05/18 01:06

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

擦护栏

题目描述

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 571744

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;}



原创粉丝点击