P1281 书的复制


题目描述

现在要把$m$本有顺序的书分给 $k$ 个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。

现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。

输入格式

第一行两个整数 $m,k$。

第二行 $m$ 个整数,第 $i$ 个整数表示第 $i$ 本书的页数。

输出格式

共 $k$ 行,每行两个整数,第 $i$ 行表示第 $i$ 个人抄写的书的起始编号和终止编号。 $k$ 行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。

样例数据

输入

9 3
1 2 3 4 5 6 7 8 9

输出

1 5
6 7
8 9

分析

前缀和相减求此人复制的时间,递归输出路径

状态转移方程$$Temp=max\left \{Dp_{i-1,p-1},Sum_j-Sum_{p-1}\right \}\\Dp_{i,j}=min\left \{Dp_{i,j},Temp\right \}$$

代码

#include 

#define Space putchar(' ')
#define Enter puts("")
#define MAXN 100010
#define int long long
#define INF 1e9

using namespace std;

typedef long long ll;
typedef double Db;

inline ll Read() {
    ll Ans = 0;
    char Ch = getchar() , Las = ' ';
    while(!isdigit(Ch)) {
        Las = Ch;
        Ch = getchar();
    }
    while(isdigit(Ch)) {
        Ans = (Ans << 3) + (Ans << 1) + Ch - '0';
        Ch = getchar();
    }
    if(Las == '-')
        Ans = -Ans;
    return Ans;
}

inline void Write(ll x) {
    if(x < 0) {
        x = -x;
        putchar('-');
    }
    if(x >= 10)
        Write(x / 10);
    putchar(x % 10 + '0');
}

int Dp[1001][1001];
int n , k;
int Sum[MAXN];
int a[MAXN];

void Print(int x , int Ans) {
    if(x == 0)
        return;
    for(int i = x; i >= 0; i--)
        if(Sum[x] - Sum[i - 1] > Ans || i == 0) {
            Print(i , Ans);
            Write(i + 1) , Space , Write(x) , Enter;
            break;
        }
}

signed main() {
    n = Read() , k = Read();
    for(int i = 1; i <= n; i++)
        a[i] = Read();
    for(int i = 1; i <= k; i++)
        for(int j = 1; j <= n; j++)
            Dp[i][j] = INF;
    for(int i = 1; i <= n; i++)
        Sum[i] = Sum[i - 1] + a[i] , Dp[1][i] = Sum[i];
    for(int i = 2; i <= k; i++)
        for(int j = 1; j <= n; j++)
            for(int p = 2; p <= j; p++) {
                int Temp = max(Dp[i - 1][p - 1] , Sum[j] - Sum[p - 1]);
                Dp[i][j] = min(Dp[i][j] , Temp);
            }
    Print(n , Dp[k][n]);
    return 0;
}

相关