• 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
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    傻瓜教程:asp.net(c#) 如何配置authentication,完成基于表单的身份验证
    ajax与php交互的get和post两种实现方式
    php 存储过程
    一万小时天才理论
    servlet阅读
    post and get
    合并两个有序数组(重新开始)
    Java参数传递问题
    一万小时(如何实现)阅读
    java IO 流的学习(我们到底能走多远系列1)
  • 原文地址:https://www.cnblogs.com/gmh77/p/13938540.html
Copyright © 2020-2023  润新知