CF1442D Sum

感觉这个结论题好神仙啊,开始还以为是 max,+\max,+ 凸包之类的东西没想到是结论题。。

一个结论:对于一个选择 kk 个数的最优状态,一定不存在多于 11 个序列被选了一部分。

我们设有两个序列选了一部分 ap,aqa_p,a_q ,同时设两个序列分别选择了 tp,tqt_p,t_q ,我们可以设 ap,tp+1aq,tq+1a_{p,t_p+1} \le a_{q,t_q+1}

然后考虑,如果我们调整 kk 个数从 ppqq 内,于是更改量就是

i=1kaq,tq+ii=1kap,tp+1i\sum_{i=1}^k a_{q,t_q + i} - \sum_{i=1}^k a_{p,t_p + 1 - i}

由于每个 aa 单增,所以

aq,tq+iaq,tq+1ap,tp+1iap,tp+1a_{q,t_q + i} \ge a_{q,t_q + 1}\\ a_{p,t_p + 1 - i} \le a_{p,t_p + 1}

所以

i=1kaq,tq+ii=1kap,tp+1iaq,tq+1ap,tp+10\sum_{i=1}^k a_{q,t_q + i} - \sum_{i=1}^k a_{p,t_p + 1 - i} \ge a_{q,t_{q} + 1} - a_{p,t_p + 1} \ge 0

所以我们直接设 y=tpy = t_p 调整,把 pp 调整空即可。

所以,任意时刻只有一个数列内部被部分选择。

于是我们对除开这个数列外的其他数列跑背包,这个数列单独背包即可。除开这个物品的背包是经典套路,可以分治解决。

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#include "queue"
using namespace std;
#define MAXN 200006
//#define int long long
#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all(x) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
typedef long long ll;
#define P 1000000007
int n , k;
vi obs[3006]; ll v[3006] , w[3006];

vector<ll> dp;
ll ans = 0;
void dq( int l , int r ) {
	if( l == r ) {
		int t = 0; ll r = 0;
		for( int x : obs[l] ) {
			++ t;
			r += x;
			ans = max( ans , dp[k - t] + r );
			if( t >= k ) break;
		}
		return;
	}
	vector<ll> tmp = dp;
	int mid = l + r >> 1;
	rep( i , l , mid ) {
		for( int j = k ; j >= v[i] ; -- j ) dp[j] = max( dp[j] , dp[j - v[i]] + w[i] );
	}
	dq( mid + 1 , r );
	dp = tmp;
	rep( i , mid + 1 , r ) {
		for( int j = k ; j >= v[i] ; -- j ) dp[j] = max( dp[j] , dp[j - v[i]] + w[i] );
	}
	dq( l , mid );
}

void solve( ) {
    cin >> n >> k;
	rep( i , 1 , n ) {
		static int t;
		scanf("%d",&t);
		obs[i].resize( t );
		rep( j , 0 , t - 1 ) scanf("%d",&obs[i][j]) , w[i] += obs[i][j];
		v[i] = t;
	}
	dp.resize( k + 1 );
	dq( 1 , n );
	cout << ans << endl;
}

signed main() {
//	freopen("input","r",stdin);
//	freopen("fuckout","w",stdout);
//    int T;cin >> T;while( T-- ) solve();
	solve();
}
\