这种题大概有两种办法:
首先思考贪心。
考虑网络流?
考虑动态规划?
思考这个问题的特征是什么
最终还是没想出来。
有一个结论:必然至多存在一个序列满足这里面只选了一个数。
如果有两个序列 \(a_x\) 和 \(a_y\) 都没有全选,设 \(a_{x,1}\sim a_{x,p}\) 都选了并且 \(a_{y,1}\sim a_{y,q}\) 都选了。不妨设 \(a_{x,p+1}>a_{y,q+1}\) ,那么 \(\sum_{i=1}^k a_{x,p+k}\ge \sum_{i=1}^ka_{y,q-i+1}\) 。即将 \(a_{y,q-k+1}\sim a_{y,q}\) 换为 \(a_{x,p+1}\sim a_{x,p+k}\) 这些数和不会更差。所以必然存在一种选法满足最多一个序列没有选满。
那么只要枚举每个序列当成没有选满的序列,然后其他序列跑背包。
考虑分治。分治树是一颗线段树,相当于在 \(\text{dfs}\) 一棵线段树。用一个 \(\text{dp}\) 数组,在刚 \(\text{dfs}\) 到这个结点的时候,\(\text{dp}\) 数组的值应该是去掉这个节点所代表的区间,剩下的所有数计算出的 \(\text{dp}\) 数组。每次 \(\text{dfs}\) 到他的两个子节点,会先加上右边一半再 \(\text{dfs}\) 左边,再从初始状态加上左边一半 \(\text{dfs}\) 右边一半。
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const long long NN = 3e3 + 5, NK = 3e3 + 5;
long long N, K, len[NN], f[NN], ans;
vector<long long> seq[NN];
void Upd(long long siz, long long val) {
for (long long i = K; i >= siz; --i) {
f[i] = max(f[i], f[i - siz] + val);
}
}
void Divide(long long L, long long R) {
if (L == R) {
for (long long i = 0; i <= min((long long)len[L], K); ++i)
ans = max(ans, f[K - i] + seq[L][i]);
return ;
}
long long mid = (L + R) / 2;
long long rec[NK];
for (long long i = 0; i <= K; ++i)
rec[i] = f[i];
for (long long i = mid + 1; i <= R; ++i)
Upd(len[i], seq[i][len[i]]);
Divide(L, mid);
for (long long i = 0; i <= K; ++i)
f[i] = rec[i];
for (long long i = L; i <= mid; ++i)
Upd(len[i], seq[i][len[i]]);
Divide(mid + 1, R);
}
int main() {
freopen("sum.in", "r", stdin);
freopen("sum.out", "w", stdout);
scanf("%lld%lld", &N, &K);
for (long long i = 1; i <= N; ++i) {
scanf("%lld", &len[i]);
seq[i].push_back(0);
for (long long j = 1; j <= len[i]; ++j) {
long long x;
scanf("%lld", &x);
seq[i].push_back(x);
}
for (long long j = 1; j <= len[i]; ++j)
seq[i][j] = seq[i][j - 1] + seq[i][j];
}
memset(f, 0x8f, sizeof(f));
f[0] = 0;
Divide(1, N);
printf("%lld\n", ans);
fclose(stdin);
fclose(stdout);
return 0;
}
需要先想到暴力,然后再想到结论,再用优化。
暴力很容易想。
可以发现如果暴力 \(g_{i,j}\) 转移的时候可以去掉枚举的复杂度,那么就不会TLE。或许这样就可以想到,如果真的每个数组要么都选,要么不都选了。这可能需要一些突发奇想,才能想到这个结论吧。
优化其实可以这样想。先想到去掉每个数后的问题有很多相同部分。然后想到用分治利用共同部分?
原文:https://www.cnblogs.com/YouthRhythms/p/13978589.html