题目大意
给出n个不减数组,每个数组可以取一段前缀,求恰好取出k个数的最大和
n,k<=3000,Σ|a|<=1e6
题解
比C阳间
显然只会有最多一个选了的数组没有选满,否则找出两个不满的可以将其调整,一定是越调越优
做法1:设f[i,j,0/1]表示当前到i选了j个,是否已经选过一个未满的,写出来后发现满足决策单调,1d1d即可
做法2:分治,设当前到[l,r]表示[1,l-1]和[r+1,n]都已经加进去的状态,最后到[i,i]时再枚举
两种做法都是O(n^2log)
code
做法2
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define ll long long
//#define file
using namespace std;
ll a[3001][3001],f[3001][3001],ans;
int b[3001],n,K,i,j,k,l;
void work(int x,int y,int tot)
{
int i,j,k,l,mid=(x+y)/2;
if (x==y)
{
fo(i,0,b[x]) ans=max(ans,f[tot][K-i]+a[x][i]);
return;
}
l=tot;
fo(i,mid+1,y)
{
memcpy(f[l+1],f[l],sizeof(f[l]));
fo(j,0,K-b[i]) f[l+1][j+b[i]]=max(f[l+1][j+b[i]],f[l][j]+a[i][b[i]]);
++l;
}
work(x,mid,l);
l=tot;
fo(i,x,mid)
{
memcpy(f[l+1],f[l],sizeof(f[l]));
fo(j,0,K-b[i]) f[l+1][j+b[i]]=max(f[l+1][j+b[i]],f[l][j]+a[i][b[i]]);
++l;
}
work(mid+1,y,l);
}
int main()
{
#ifdef file
freopen("CF1442D.in","r",stdin);
#endif
scanf("%d%d",&n,&K);
fo(i,1,n)
{
scanf("%d",&b[i]);
fo(j,1,b[i])
{
if (j<=K) scanf("%lld",&a[i][j]);
else scanf("%d",&k);
}
b[i]=min(b[i],K);
}
fo(i,1,n) fo(j,1,b[i]) a[i][j]+=a[i][j-1];
work(1,n,0);
printf("%lld
",ans);
fclose(stdin);
fclose(stdout);
return 0;
}