CF1442D. Sum

题目大意

给出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\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-11-06 19:19  gmh77  阅读(231)  评论(0编辑  收藏  举报