题目1502:最大值最小化
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:591
解决:229
题目描述:
在印刷术发明之前,复制一本书是一个很困难的工作,工作量很大,而且需要大家的积极配合来抄写一本书,团队合作能力很重要。
当时都是通过招募抄写员来进行书本的录入和复制工作的, 假设现在要抄写m本书,编号为1,2,3...m, 每本书有1<=x<=100000页, 把这些书分配给k个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的。每个抄写员的速度是相同的,你的任务就是找到一个最佳的分配方案,使得所有书被抄完所用的时间最少。
输入:
输入可能包含多个测试样例。
第一行仅包含正整数 n,表示测试案例的个数。
对于每个测试案例,每个案例由两行组成,在第一行中,有两个整数m和 k, 1<=k<=m<=500。 在第二行中,有m个整数用空格分隔。 所有这些值都为正且小于100000。
输出:
对应每个测试案例,
输出一行数字,代表最佳的分配方案全部抄写完毕所需要的时间。
样例输入:
2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100
样例输出:
1700
200
来源:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
解题思路:二分所有的可行解(元素最大值maxx~元素和sum),然后扫描原序列进行验证
复杂度分析:二分可行解——O(log(sum))
扫描原序列——O(M)
故求解复杂度为——O(M*log(sum) )
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
int a[505];
int n, k, m;
bool judge(int x)
{
int s = 0; //记录当前所选序列的总和、
int cnt = 0; //记录现在所选择的序列数,从而与 k进行比较
for(int i=0; i<m; i++)
{
if(x < a[i]) return false;
if(s+a[i] <= x)
{
s += a[i];
}
else{
s = a[i];
cnt++;
if(cnt > k-1) return false;
}
}
return true;
}
int solve(int left, int right)
{
int mid;
while(left < right)
{
mid = left+(right-left)/2;
if(judge(mid)) right = mid;
else left = mid+1;
}
return left;
}
int main()
{
int maxx = 0, sum = 0;
scanf("%d", &n);
while(n--)
{
maxx = sum = 0;
scanf("%d%d", &m, &k);
for(int i=0; i<m ;i++)
{
scanf("%d", a+i);
if(a[i] > maxx) maxx = a[i];
sum += a[i];
}
printf("%d\n", solve(maxx, sum));
}
return 0;
}