题目大意:
要抄N本书,编号为1,2,3…N, 每本书有1<=x<=10000000页, 把这些书分配给K个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的。每个抄写员的速度是相同的,求所有书抄完所用的最少时间的分配方案。
Sample Input
2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100
Sample Output
100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100
分析与总结:
所化的总时间取决于所有抄写员中任务最多的那个,是经典的最大值最小化问题。在这题中,需要注意的是求和时用32位int可能会溢出,所以要用long long.
#include<cstdio>
#include<cstring>
#define MAXN 505
using namespace std;
int m, k;
long long arr[MAXN], sum, min, ans;
bool vis[MAXN];
int divide(long long M){
memset(vis, 0, sizeof(vis));
int cnt=0;//用于记录当前方案需要的人数
int pos=m-1;//从后往前分解
while(pos>=0){
long long sum=0;
while(pos>=0 && sum+arr[pos]<=M){
sum += arr[pos];
--pos;
}
if(pos>=0) vis[pos] = true;
++cnt;
}
return cnt;
}
long long binary(){
long long left=min, right=sum, mid;//left用于记录最少,right用于记录最多所花的时间,mid则采用二分法来计算花时间最少的人
while(left<right){
mid = (left+right)>>1;
if(divide(mid)<=k)
right=mid;
else
left=mid+1;
}
return right;
}
void output(){
int cnt=divide(ans);
for(int i=0; i<m-1&&cnt<k; ++i)if(!vis[i]){
vis[i]=true;
++cnt;
}
for(int i=0; i<m; ++i){
if(i) printf(" %lld",arr[i]);
else printf("%lld",arr[i]);
if(vis[i]){
printf(" /");
}
}
puts("");
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&m,&k);
sum=0; min=0;
for(int i=0; i<m; ++i){
scanf("%lld",&arr[i]);
sum += arr[i];
if(arr[i]>min) min=arr[i];
//这里需要和binary()函数一起分析,min是指一个工人最少看的页数,不可能少于这个数,因为此题算的是所有人中花的时间最多的人
}
ans=binary();
output();
}
return 0;
}