先二分判断这些抄写员中需要抄书最多的,抄书的数目。对某一个可能的枚举值x,以x为区间元素和的最大值去划分完整的区间,如果发现划的斜杠数小于等于k-1,即符合题意。那么抄书最多的那个人抄书的数目一定小于等于x,以x作为右边界继续二分,否则将x作为左边界。计算出最小的最大值后考虑输出,先从后向前划斜杠,使得越靠前的抄写员抄的书越少,如果发现斜杠划少了就从头遍历每一个位置,一旦发现这个位置没划斜杠就把他划上斜杠直到斜杠画满为止(一共要画k-1个斜杠)。
AC代码如下
#include <cstdio>
#include <cstring>
using namespace std;
int s[505],n,k;
bool pos[505];
bool smaller(int x)
{
int sum=0,cnt=0;
for(int i=0;i<n;i++)
{
sum+=s[i];
if(sum>x)
{
sum=0;
i--;
cnt++;
if(cnt>k-1) return false;
}
}
return true;
}
void print_ans(int maxx)
{
memset(pos,false,sizeof(pos));
int sum=0,cnt=0;
for(int i=n-1;i>=0;i--)
{
sum+=s[i];
if(sum>maxx)
{
pos[i++]=true;
cnt++;
sum=0;
}
}
int i=0;
while(cnt<k-1&&i<n)
{
if(!pos[i])
{
pos[i]=true;
cnt++;
}
i++;
}
printf("%d", s[0]);
if(pos[0]) printf(" /");
for(int i=1;i<n;i++)
{
printf(" %d", s[i]);
if(pos[i]) printf(" /");
}
printf("\n");
}
int main(int argc, char const *argv[])
{
int T;
scanf("%d", &T);
while(T--)
{
int sum=0;
scanf("%d %d", &n, &k);
for(int i=0;i<n;i++)
{
scanf("%d", &s[i]);
sum+=s[i];
}
int L=0,R=sum;
while(R-L>1)
{
int t=(L+R)/2;
if(smaller(t))
R=t;
else
L=t;
}
print_ans(R);
}
return 0;
}