CF1442 D. Sum

89 篇文章 1 订阅

CF1442 D. Sum

首先可以发现,最终选择的结果一定是某一个数组选择了前几个,其它的数组要么全选,要么全不选。不然若存在两个都只选择了一部分的,结尾大的向后延申一个,小的向前一个答案一定更优。

这样我们就可以枚举只拿一部分的物品,其他01背包就行了。时间复杂度为 O ( n 2 × k ) O(n^2\times k) O(n2×k),TLE。

但我们仔细分析一下就能发现,若我们第 i i i个物品只拿一部分,然后要对 i + 1 i+1 i+1到n做一次01背包,1到i-1做一次01背包。若枚举i+1只拿一部分,要对i+2到n做一次01背包,要对1到i做一次01背包。我们发现这之间有一部分是重复计算的,会非常浪费。所以我们可以分治来解决。

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=3e3+20;
vector<LL> a[MAXN];
int t[MAXN];
LL sum[MAXN];
int n,k;
vector<LL> dfs(int l,int r){
	vector<LL> v(k+1,0);
	if(l>r) return v;
	if(l==r){
		return a[l];
	}
	vector<LL> L,R;
	int mid=(l+r)>>1;
	L=dfs(l,mid);
	rb(i,mid+1,r){
		rl(j,k,t[i])
			check_max(L[j],L[j-t[i]]+sum[i]);
	}	
	R=dfs(mid+1,r);
	rb(i,l,mid){
		rl(j,k,t[i])
			check_max(R[j],R[j-t[i]]+sum[i]);
	}
	rb(i,0,k)
		v[i]=max(L[i],R[i]);
	return v;
}
int main(){
	scanf("%d%d",&n,&k);
	rb(i,1,n) {
		int ti;
		scanf("%d",&ti);
		a[i].PB(0);
		rb(j,1,ti){
			int ai;
			scanf("%d",&ai);
			a[i].PB(ai);
			if(j<=k)
				sum[i]+=ai;
		}
		t[i]=min(k,ti);
		LL sum=0;
		for(auto& it : a[i]){
			sum+=it;
			it=sum;	
		}	
		a[i].resize(k+1);
		LL ma=0;
		for(auto& it : a[i]){
			check_max(ma,it);
			it=ma;
		}
	}
	vector<LL> rest=dfs(1,n);
	cout<<rest[k]<<endl;
	return 0;
}
/** 程序框架:
  *
  *
  *
  *
  **/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值