[二分+贪心]P1281 书的复制 题解
好经典的题目,记得之前用贪心做过。
书的复制
题目背景
大多数人的错误原因:尽可能让前面的人少抄写,如果前几个人可以不写则不写,对应的人输出 0 0
。
不过,已经修改数据,保证每个人都有活可干。
题目描述
现在要把 \(m\) 本有顺序的书分给 \(k\) 个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。
现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。
输入格式
第一行两个整数 \(m,k\)。
第二行 \(m\) 个整数,第 \(i\) 个整数表示第 \(i\) 本书的页数。
输出格式
共 \(k\) 行,每行两个整数,第 \(i\) 行表示第 \(i\) 个人抄写的书的起始编号和终止编号。 \(k\) 行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。
样例 #1
样例输入 #1
9 3
1 2 3 4 5 6 7 8 9
样例输出 #1
1 5
6 7
8 9
提示
\(1\le k \le m \le 500\)。
做时思路
有一个非常重要的点,就是书是有顺序的并且必须连续。
我们应该如何应用这个点。
令 \(dp_{i,j}\) 表示现在是第 \(i\) 个人,然后已经到第 \(j\) 本书了。
考虑一下状态转移,时间很够,我们大可以用一个 \(n^3\) 的做法乱搞。
枚举一下这个人抄到第 \(j\) 本书的情况。上一个人抄到第 \(i\) 本书。
似乎 \(n^3\) 怎么搞都可以过。。。代码不好写怎么办,直接二分贪心乱搞。
代码
#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
t=0; register char ch=getchar(); register int fflag=1;
while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
const int MAXN=505;
int n,m,a[MAXN];
int sta[MAXN],en[MAXN];
bool check(int k){
int j=n;
for(int i=m;i>=1;--i){
int res=k;
en[i]=j;
while(j){
res-=a[j];
if(res<0){
sta[i]=j+1;
break;
}
--j;
}
}
if(j==0) return 1;
return 0;
}
int main(){
read(n,m);
for(int i=1;i<=n;++i) read(a[i]);
int l=0,r=1000000000;
while(l<r){
//[l,r]
//cout<<l<<' '<<r<<endl;
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
check(l);
sta[1]=1;
for(int i=1;i<=m;++i) cout<<sta[i]<<' '<<en[i]<<endl;
return 0;
}
//Welcome back,Chtholly.