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 <bits/stdc++.h> #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; }