记录一下这题坑点。
题面一看最大值尽可能小,划分成k块,明显是二分。
既然是k块,需要划分k-1刀
坑点:二分return true的时候,可能划分根本不足k块,需要按题意从左到右“补刀”
记录此题提醒自己二分的时候注意题目挖下的陷阱,往往就隐藏在输出的要求之中,一开始看到要最左边尽可能小,我只想到了从右往左开始遍历,并没有想到此处暗含一个坑
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define int long long
int a[550];
bool vis[550];
bool vis2[550];
int n, k;
bool judge(int x)
{
memset(vis, 0, sizeof(vis));
int tot = 0;
int cnt = 0;
for (int i = n; i >= 1; i--)
{
if (tot + a[i] <= x) tot += a[i];
else cnt++, tot = a[i], vis[i] = true;
}
if (cnt <= k-1) {
memcpy(vis2, vis, sizeof(vis));
if (cnt < k - 1) {//这里贼坑 debug好久才发现 划分块数不足需要补充
for (int i = 1; i <= n; i++)
{
if (!vis2[i]) {
vis2[i] = true; cnt++;
}
if (cnt == k - 1) return true;
}
}
return true;
}//成功划分 说明x大了
else return false;//划分失败 说明x小了
}
signed main()
{
int t;
scanf("%lld", &t);
while (t--)
{
memset(vis2, 0, sizeof(vis2));
scanf("%lld%lld", &n, &k);
int l=0, r=0;
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
l = max(l, a[i]);
r += a[i];
}
int mid;
while (l < r)
{
mid = (l + r) >> 1;
if (judge(mid)) r = mid;
else l = mid + 1;
}
for (int i = 1; i <= n; i++)
{
if (i == 1) printf("%lld", a[i]);
else printf(" %lld", a[i]);
if (vis2[i]&&i!=n) printf(" /");
}
printf("\n");
}
}