【题解】CF1442D Sum

前言:

麻了,这都想不到。

复课后整个人搞 OI 时的专注和认真的态度都少了很多,可能是 csp 和 noip 过了,没有考试了,或是题停课时考试成绩有所提高,得意忘形了。今后必须要严格按照做题技巧上面来,认真总结做题技巧,积累套路,再糊弄就要退役了。

描述:

给定 \(n\) 个不降的数组。有一个值 \(ans\),初始为 \(0\)。你需要进行如下操作 \(k\) 次:

选择一个数组,把 \(ans\) 加上数组的第一个元素,之后把它删除。

请求出 \(ans\) 最大是多少。

所有数组的元素总个数 \(\leq 10^6\),\(n,k\leq 3000\)。

思路:

考虑从特殊情况推广到一般情况。对于 \(n=2\) ,发现最优解不可能出现两个序列都取了但没取完的情况。

因为序列 不降 ,假如 \(a_i>b_i\) ,那么可以加入 \(a_{i+1}\) ,删除 \(b_i\) ,反之同理。

考虑将 \(n=2\) 推广到一般情况,感性证明可以发现无论何时,顶多只有 \(1\) 个序列取了但没取完。

考虑分治,分治到 \(l=r\) 的情况时更新答案。

代码:

#include <bits/stdc++.h>

#define LL long long
#define DB double
#define PR pair <int, int>
#define MK make_pair
#define pb push_back
#define fi first
#define se second
#define RI register int
#define Low(x) (x & (-x))

using namespace std;

const int kN = 3e5 + 5;

int n, K, num[kN]; LL val[kN], ans;
vector <int> a[kN];
vector <LL> f;

void Solve(int l, int r) {
  if (l == r) {
    LL sum = 0;
    for (int i = 0; i < num[l]; ++i) {
      sum += a[l][i];
      ans = max(ans, f[K - (i + 1)] + sum);
      if (i + 1 >= K) break;
    }
    return;
  }
  int mid = (l + r) >> 1;
  vector <LL> tmp = f;
  for (int i = l; i <= mid; ++i)
    for (int j = K; j >= num[i]; --j)
      f[j] = max(f[j], f[j - num[i]] + val[i]);
  Solve(mid + 1, r);
  f = tmp;
  for (int i = mid + 1; i <= r; ++i)
    for (int j = K; j >= num[i]; --j)
      f[j] = max(f[j], f[j - num[i]] + val[i]);
  Solve(l, mid);
}

signed main() {
  scanf("%d%d", &n, &K);
  for (int i = 1; i <= n; ++i) {
    scanf("%d", &num[i]);
    for (int j = 0; j < num[i]; ++j) {
      a[i].pb(0), scanf("%d", &a[i][j]), val[i] += a[i][j];
    }
  }
  for (int i = 1; i <= K; ++i) f.pb(0);
  Solve(1, n);
  printf("%lld\n", ans);
  return 0;
}

上一篇:CAD通过XCLIP命令插入DWG参照裁剪图形,引用局部图像效果(CAD裁剪任意区域)


下一篇:【题解】P3149 排序 & test10.27 T1 sort