[二分+贪心]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.
posted @ 2022-07-08 17:01  Mercury_City  阅读(70)  评论(0编辑  收藏  举报