https://www.luogu.org/blog/cccx2016/solution-p1281
动态规划+贪心
1、f[i][j]存的是前i本书分给第j个人,记录前缀和,初始化f[i][1]数组。
2、三重循环更新f数组,k代表最后一个人拿第一本书的编号,前后比较最大值与之前答案最小值更新f数组。
3、输出答案。使用贪心,因为要求前面的人尽量少抄写,所以我们可以记录读入数据之和来更新,最后得到答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
using namespace std;
const int maxn=510;
int f[maxn][maxn];
int in[maxn],sum[maxn];
int n,m;
void ff()
{
for(int j=2;j<=m;j++)
{
for(int i=j;i<=n;i++)
{
for(int k=j;k<=i;k++)
{
int ans=0;
ans=max(f[k-1][j-1],sum[i]-sum[k-1]);
f[i][j]=min(f[i][j],ans);
}
}
}
}
void print(int l,int r)
{
int ss=0;
for(int i=r;i>=l;i--)
{
if(ss+in[i]>f[n][m])
{
print(l,i);
printf("%d %d\n",i+1,r);
return ;
}
ss+=in[i];
}
printf("%d %d\n",1,r);
}
int main()
{
memset(sum,0,sizeof(sum));
memset(f,0x3f3f3f,sizeof(f));
scanf("%d%d",&n,&m);
if(n==0) return 0;
for(int i=1;i<=n;i++)
{
scanf("%d",&in[i]);
sum[i]=in[i]+sum[i-1];
f[i][1]=sum[i];
}
ff();
print(1,n);
return 0;
}