abc366_f

思路

考虑 \(dp\),那么我们就需要装压 \(dp\),所以我们考虑是否可以通过改变拓扑序,来让题目变成我们熟悉的背包 \(dp\),所以我们来思考一下,什么时候交换顺序反而更优?

考虑 \(i\)\(i + 1\),那么如果为 \(f_{i+1}(f_i(x))\) 那么贡献为:

\(a_{i+1}(a_{i}x+b_{i})+b_{i+1}\)

如果交换那么贡献为:

\(a_{i}(a_{i+1}x+b_{i + 1}) + b_{i}\)

那么如果可以交换,我们便可以通过两个式子的比较来算出比较器该怎么写。

可是我们怎么保证这是对的呢?考虑到这个式子的形式,对于之前的我们将视之为 \(x\),所以不会因为现在的变动改变之前的,对于后面的,我们的变动,对于后面的只是 \(x\) 的变动,对于决策不产生影响,所以这个交换是可行的。

code

#include <algorithm>
#include <iostream>
#include <cstring>

using namespace std;
using ll = long long;

const int MaxN = 1e6 + 10;

struct S {
  ll a, b;

  bool operator<(const S &j) const {
    return (j.a - 1) * b > (a - 1) * j.b;
  }
} a[MaxN];

ll f[MaxN][20], n, k;

int main() {
  cin >> n >> k;
  for (int i = 1; i <= n; i++) {
    cin >> a[i].a >> a[i].b;
  }
  sort(a + 1, a + n + 1);
  memset(f, -1, sizeof(f));
  f[0][0] = 1;
  for (int i = 1; i <= n; i++) {
    for (int j = 0; j <= k; j++) {
      f[i][j] = f[i - 1][j];
      (j && f[i - 1][j - 1] >= 0) && (f[i][j] = max(f[i][j], a[i].a * f[i - 1][j - 1] + a[i].b));
    }
  }
  cout << f[n][k] << endl;
  return 0;
}
posted @ 2024-08-21 21:33  yabnto  阅读(4)  评论(0编辑  收藏  举报