Educational Codeforces Round 122 (Rated for Div. 2) D. Make Them Equal

题面

题意

  • 一开始有一个全部都是 1 的序列 a a a,你可以执行以下操作。

    选择序列中的一个数 a i a_i ai,一个数 x x x a i = a i + a i x a_i=a_i+\dfrac{a_i}{x} ai=ai+xai

    如果经过多次操作后, a i = b i a_i=b_i ai=bi,你就可以获得 c i c_i ci 的价值。

    问经过 k k k 次操作后,获得的价值最大是多少。

    n ≤ 1 0 3 , k ≤ 1 0 6 , b i ≤ 1 0 3 , c i ≤ 1 0 6 n\le10^3,k\le10^6,b_i\le10^3,c_i\le10^6 n103,k106,bi103,ci106

思路

  1. 最大价值,想到背包,看看花费是什么,是操作数,现在问题变成求从 1 到 x 的最少操作数,可以利用 O ( ( max ⁡ b i ) 2 ) ≈ 1 0 6 O((\max b_i)^2)\approx 10^6 O((maxbi)2)106 的最短路暴力预处理。
  2. 最短路预处理时,当当前数 > 1000 时就不再继续扩展最短路。
  3. 然后跑一个 01 背包。
  4. 预处理后知, v i ≤ 12 v_i\le 12 vi12。所以背包体积取个min: chkmin(V, 12 * n), 可以优化复杂度至: O ( n ⋅ min ⁡ ( k , 12 × n ) ) ≈ 1 0 7 O(n\cdot\min(k,12\times n)) \approx10^7 O(nmin(k,12×n))107,可以通过。

代码

const int N = 1e6 + 5;

int n, V, v[N], w[N], b[N], f[N];

int main() {
    mst(v, 0x3f); v[1] = 0;
    queue<pii> q;
    q.push({1, 0});
    while(!q.empty()) {
        auto [u, d] = q.front(); q.pop();
        rep(i, 1, u) {
            int t = u + u / i;
            if(t > 1000) continue;
            if(v[t] > v[u] + 1) {
                v[t] = v[u] + 1;
                q.push({t, v[t]});
            }
        }
    }
    int T; cin >> T;
    while(T--) {
        mst(f, 0);
        cin >> n >> V;
        rep(i, 1, n) cin >> b[i];
        rep(i, 1, n) cin >> w[i];
        chkmin(V, 12 * n);
        rep(i, 1, n) per(j, V, v[b[i]]) chkmax(f[j], f[j - v[b[i]]] + w[i]);
        cout << f[V] << endl;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值