题意:题目给出N个城市和B个邮箱,接下里输入N个城市的人口数量,对于每一个城市,需要给出至少一个邮箱方便选民寄信,我们所要做的就是,将邮箱按照一定要求分配给各个城市,使得装有最多信封的邮箱中的信封同比其他方案下最多信封的邮箱中的信封数是最少的(有那么点绕,简而言之就是相当于使得最大值最小)。
思路还是很明确的,跟Pie的那道题(我的解题链接(详解))差不多,在这里,我还是会给出详解:
我们已知的就是N,B,与ai,我想到的方法就是把他们之间相互的关系连接在一起,譬如我们假设一个答案x,那么我们可以把ai从0~N-1逐步求与x整除的和sum(如果不能整除,则和再+1),如果sum>B,则说明我们给出的x偏小,反之则可能偏大或者取等时有可能为正确答案。——于是,就有了二分的思想。
主要函数:
while(left<=right) { int sum=0; mid=(left+right)/2; for(int i=0; i<N; i++) { sum+=a[i]/mid; if(a[i]%mid) { ++sum; } } if(sum>B) { left=mid+1; } else { right=mid-1; } }
在此处,用“sum>B”作为判断语句是有讲究的,我们此处不能用“sum>=B”,因为我们要输出的是最后得到的left,故假如我们在“sum==B”的时候还在继续判断,有可能使得达到的答案超出范围,我们要的是让left逐渐逼近正确答案值,当“left>right”时跳出循环那么那时候得到的答案肯定就是我们所要求的答案了(因为left-1那时候还可以继续判断,而再加下来就是答案left,刚好是所要求的答案)。
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int a[500001]; int N,B; int main() { while(scanf("%d%d",&N,&B)) { if(N==-1 && B==-1)break; memset(a, 0, sizeof(a)); int maxx=0; for(int i=0; i<N; i++) { scanf("%d",&a[i]); if(maxx<a[i]) maxx=a[i]; } int left=0,right=maxx; int mid=0; while(left<=right) { int sum=0; mid=(left+right)/2; for(int i=0; i<N; i++) { sum+=a[i]/mid; if(a[i]%mid) { ++sum; } } if(sum>B) { left=mid+1; } else { right=mid-1; } } printf("%d\n",left); } return 0; }