codevs 3162 抄书问题
3162 抄书问题
题目描述 Description
现在要把M本有顺序的书分给K个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本数给同一个人抄写。现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。
输入描述 Input Description
第一行两个整数M、K;(K<=M<=100)
第二行M个整数,第i个整数表示第i本书的页数。
输出描述 Output Description
共K行,每行两个正整数,第i行表示第i个人抄写的书的起始编号和终止编号。K行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。
样例输入 Sample Input
9 3
1 2 3 4 5 6 7 8 9
样例输出 Sample Output
1 5
6 7
8 9
f[i][j] 表示抄到第j本书,用了i个人的时候,抄的最多的人最少抄多少
f[i][j]=min(max( f[k-1][j-1],sum[i]-sum[k])) sum[]是维护的前缀和
求出f[n][K-1]即n本书 分给K个人抄,抄的最多的人 最少抄多少,
题目要求靠前的人尽可能抄的少
那么 从后往前扫一遍,从后往前 分成一个个区间,每个区间不超过f[n][K-1]就行
#include<iostream> #include<cstring> using namespace std; int n,m,a[110],sum[110],dp[110][110],cnt; struct node{ int l,r; }s[110]; int main(){ cin>>n>>m; if(n==0)return 0; memset(dp,127/3,sizeof(dp)); for(int i=1;i<=n;i++){ cin>>a[i];sum[i]=sum[i-1]+a[i]; dp[i][1]=sum[i]; } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ for(int k=i;k>=1;k--){ dp[i][j]=min(dp[i][j],max(dp[k-1][j-1],sum[i]-sum[k-1])); } } } int ans=dp[n][m]; int sum=0,c=n; for(int i=n;i>=1;i--){ sum+=a[i]; if(sum>ans){ s[++cnt].l=i+1; s[cnt].r=c; c=i; sum=a[i]; } } if(cnt!=0){ cout<<1<<' '<<max(1,s[cnt].l-1)<<endl; for(int i=cnt;i>=1;i--){ cout<<s[i].l<<' '<<s[i].r<<endl; } } if(cnt==0){ cout<<1<<' '<<n; } }