题目:https://www.luogu.org/problemnew/show/P1281
很容易想到模板:乘积最大
f[i,j]=min(max(f[k-1,j-1],sum[k...i])) 循环k:最后一个人复制k~i的书
f[i,j] 前i本书j个抄写员最短的最长用时。。。二维就可以了
50分代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxSize=500,maxValue=0x7fffffff;
int m,k1;
int a[maxSize+5],sum[maxSize+5],f[maxSize+5][maxSize+5];//前i本书j个人写
int ans[maxSize+5][maxSize+5],ans1[maxSize+5];
void dp()
{
int i,j,k,max1,temp;
for (j=1;j<=k1;j++)//前j个抄写员
{
for (i=j;i<=m;i++)//i本书
{
if (j==1)
{
f[i][1]=sum[i];
continue;
}
f[i][j]=maxValue;
for (k=j;k<=i;k++)//k:最后一个人拿的第一本
{
max1=max(f[k-1][j-1],sum[i]-sum[k-1]);
if (f[i][j]>max1)
{
f[i][j]=max1;
ans[i][j]=k;
}
}
}
}
temp=m;
for (i=k1;i>1;i--)
{
ans1[i]=ans[temp][i]-1;
temp=ans1[i];
}
temp=1; ans1[k1+1]=m;
for (i=1;i<=k1;i++)
{
// printf("%d\n",ans1[i]);
printf("%d %d\n",temp,ans1[i+1]);
temp=ans1[i+1]+1;
}
}
int main()
{
int i;
freopen("a.txt","r",stdin);
scanf("%d%d",&m,&k1);
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
memset(sum,0,sizeof(sum));
for (i=1;i<=m;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
dp();
return 0;
}
输出有问题。。。要求越后面的人尽可能多的复制书。。。
用一波贪心。。。从后往前搜小于答案的
an=f[m][k1];
temp=m; j=k1;
for (i=m;i>=1;i--)
{
if (sum[temp]-sum[i-1]>an)
{
ans1[j]=i+1;
temp=i;
j--;
if (j==1)
break;
}
}
ans1[1]=1; ans1[k1+1]=m+1;
for (i=1;i<=k1;i++)
{
printf("%d %d\n",ans1[i],ans1[i+1]-1);
}