洛谷绿题
题目传送门
题目背景
大多数人的错误原因:尽可能让前面的人少抄写,如果前几个人可以不写则不写,对应的人输出 0 0 。
不过,已经修改数据,保证每个人都有活可干。
题目描述
现在要把 m 本有顺序的书分给 k 个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。
现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。
输入格式
第一行两个整数 m,k。
第二行 m 个整数,第 i 个整数表示第 i 本书的页数。
输出格式
共 k 行,每行两个整数,第 i 行表示第 i 个人抄写的书的起始编号和终止编号。 k行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。
#include<cstdio>
#include<cstring>
int n,m,ans;
int a[510];
bool ch(int x) {
int su=0,an=0;//an表示能分几个人
//printf("%d\n",x);
for(int i=n; i>=1; i--) {
if(i==1) an++; //最后一人(最前面的)需要特殊处理
if(su+a[i]<=x) {
su+=a[i];
} else {
an++;
su=a[i];
}
}
if(an<=m) return 1;
return 0;
}
void pr(int l,int r) { //打印当前左右边界内的部分
int ss=0;
for(int i=r; i>=l; i--) {
if(ss+a[i]>ans) {
pr(l,i);
printf("%d %d\n",i+1,r);//逆序输出,回溯时才打印
return ;
}
ss+=a[i];
}
printf("%d %d\n",1,r);//关于第一个人的特殊处理(边界)
//第一组是不会超tim的
}
int main() {
scanf("%d %d",&n,&m);
if(n==0) return 0;// 判 0 的坑点,我wa了3次
int l=0,r,mid;
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
r+=a[i];
}
// 二分模板
while(l<=r) {
mid=(l+r)/2;
if(ch(mid)) {
ans=mid; //ans存的就是每个人能分到的页数最大值,用这个来判输出
r=mid-1;
} else l=mid+1;
}
//printf("%d\n",ans);
pr(1,n);// 打印函数(我用递归来实现的,直接倒推打循环也是可以的)
return 0;
}