题意:
现在要把m本有顺序的书分给k个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三和第四本书给同一个人抄写。现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。如果有多组解的话先要保证第一个人抄的尽量少,若仍有多组解,要先保证第二个人抄的尽量少,以此类推。要注意一下,保证前面的尽量小,前面的也要有的抄。
思路:
经典的二分答案+验证的题目。分析题目的单调性,设抄写页数最多的人用去的时间为x,考虑x很小的时候,能写完的书的数量y一定很小,随着x变大,每个人分到的书的数量会增加,能完成的书的总量就会增加,所以x递增时,y递增,满足单调性。然后,二分枚举x,找到最小的x,使y >= m 成立。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll inf = 1e17;
ll a1[510], is[510];
int n, m;
bool check(ll val){
ll s = 0, cnt = 1;
for(int i = 1; i <= n; i ++){
if(a1[i] > val) return false;
if(s+a1[i] <= val) s += a1[i];
else cnt ++, s = a1[i];
}
return cnt <= m;
}
int main(){
int T;
scanf("%d", &T);
while(T --){
memset(is, 0, sizeof is);
ll l = inf, r = 0, ans = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
scanf("%d", &a1[i]), l = min(l, a1[i]), r += a1[i];
while(l <= r){
ll mid = (l+r)>>1;
if(check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
ll s = 0;
int now = m;
is[0] = 1;
for(int i = n; i >= 1; i --){
if(i >= now && a1[i]+s <= ans) s += a1[i];
else s = a1[i], now --;
is[i] = now;
}
for(int i = 1; i <= n; i ++){
if(is[i] != is[i-1]) printf("/ ");
printf("%I64d ", a1[i]);
}
printf("\n");
}
return 0;
}