题目描述 Description
现在要把M本有顺序的书分给K个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比 如不能把第一、第三、第四本数给同一个人抄写。现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。
(本题数据范围扩大,本题支持 O(nk) 算法)
输入描述 Input Description
第一行两个整数M、K;(K<=1000 M<=10000 满足 k<=m)
第二行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
数据范围及提示 Data Size & Hint
详见试题
本题支持 O(nk) 算法
分类标签 Tags 点此展开
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define f(a,b) (sum[b]-sum[a-1])
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn=1000 ;
const int maxm=10000 ;
int dp[maxn+5][maxm+5],a[maxm+5];
int n,m;
int sum[maxm+5];
int ans;
void print(int num ,int v)
{
int best;
if(num==1) {printf("%d %d\n",1,v);return;}
for(int k=num-1;k<v;k++)
{
int ret=max(dp[num-1][k],sum[v]-sum[k]);
if(ret<=ans )
{
best=k;
break;
}
}
print(num-1,best);
printf("%d %d\n",best+1,v);
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
if(m==0)
{
continue;
}
sum[0]=0;
for(int i=1;i<=m;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
dp[1][i]=sum[i];
}
for(int i=2;i<=n;i++)//i个人
{
int k=i;
dp[i][k]=max(dp[i-1][k-1], a[k] );
for(int j=i+1;j<=m-(n-i) ;j++ )
{
if( f(k,j)<=dp[i-1][k-1] )
{
dp[i][j]=dp[i-1][k-1] ;
}
else if( a[j]>=dp[i-1][j-1] )
{
dp[i][j]=a[j];
k=j;
}
else
{
while( f(k+1,j)>=dp[i-1][k] ) k++;
dp[i][j]=min( f(k,j),dp[i-1][k]);
if( dp[i][j]== dp[i-1][k] ) k++;
}
}
}
ans=dp[n][m];
print(n,m);
}
return 0;
}