题目背景
大多数人的错误原因:尽可能让前面的人少抄写,如果前几个人可以不写则不写,对应的人输出0 0。
不过,已经修改数据,保证每个人都有活可干。
题目描述
现在要把m本有顺序的书分给k给人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。
现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。
输入输出格式
输入格式:
第一行两个整数m,k;(k≤m≤500)
第二行m个整数,第i个整数表示第i本书的页数。
输出格式:
共k行,每行两个整数,第i行表示第i个人抄写的书的起始编号和终止编号。k行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。
输入输出样例
输入样例#1: 复制
9 3 1 2 3 4 5 6 7 8 9
输出样例#1: 复制
1 5 6 7 8 9
思路
既然是让求每个人抄写的书数,其实也就是求所有人抄写页数中的最大值,我们只要保证前面的人抄写的页数尽量最少即可,故我们可以从后往前遍历,让后面的人尽量多复制几本。其中,抄写的页数是关键,我们可以利用二分来实现遍历。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cstdio> using namespace std; int a[505]; int m,k; bool judge(int x) // x抄写的页数 { int sum=0,num=0; for(int i=m;i>=1;i--){ // 从后往前遍历 sum+=a[i]; if(sum>x){ num++; sum=a[i]; } } num++; return num<=k; } struct node { int l,r; }s[505]; int main() { scanf("%d%d",&m,&k); int sum=0,i,num; for(i=1;i<=m;i++){ scanf("%d",&a[i]); sum+=a[i]; } int l=0,r=sum; // 简单二分 while(r>=l){ int mid=(l+r)/2; if(judge(mid))r=mid-1; else l=mid+1; } // cout << l << endl; 验证 sum=0,num=m; int p=k; for(int i=m;i>=1;i--){ sum+=a[i]; if(sum>l){ sum=a[i]; s[p].l=i+1;s[p--].r=num; //进行存储 num=i; // 标记 } } s[1].l=1;s[1].r=num; for(int i=1;i<=k;i++) printf("%d %d\n",s[i].l,s[i].r); return 0; } |