zoukankan      html  css  js  c++  java
  • [CF1458B] Glass Half Spilled

    [CF1458B] Glass Half Spilled

    Description

    (n le 100) 杯水,其中第 (i) 杯有容积 (a_i le 100) 单位,初始时装有 (b_i) 单位的水,可以进行若干次操作,每次选择一杯水的一定水量并倒到另一杯水中,每倒一次水,倒的水会有一半洒在地上,对于所有整数 (p) 满足 (1leq pleq n),求出进行若干次操作后选取 (p) 个杯子能获得水单位数量的最大值。

    Solution

    单独考虑每个询问,显然我们划分为两个集合 A,B,将 B 中的所有水往 A 里倒,看够不够。问题是,A 如何选择不能简单按照 ai 或者 bi 来考虑
    对于一个选择,所有 A 中的 a 和为 sum_a,所有 A 中 b 和为 sum_b,总的 b 和为 tot_b,那么答案为 min((sum_b+tot_b)/2, sum_a)

    考虑一个背包,用 sum_a 作为容量,用 sum_b 作为权值,对于一个确定的 sum_a 我们想要的 sum_b 很显然会是最大的那个

    (f[i][j]) 表示考虑了前 i 杯水,(sum_a=j) 时,(sum_b) 最大可以为多少,转移时无非就是枚举当前这一杯选还是不选

    但这样没有办法解决杯数的问题

    因此我们再加一维状态

    (f[i][j][k]) 表示考虑了前 i 杯水,选了 j 个杯子当作最后的容器(也就是 sum 中的),切 (sum_a=k)(sum_b) 最大可以是多少

    那么最后,对于 p 的答案,我们只要从所有 j 个 p 的所有状态中选取最大即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 105;
    const int M = 10005;
    
    int f[N][M], n, m, a[N], b[N];
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin >> n;
        memset(f, 0xC0, sizeof f);
        f[0][0] = 0;
        int tot_b = 0;
        for (int i = 1; i <= n; i++)
            cin >> a[i] >> b[i], tot_b += b[i];
        for (int i = 1; i <= n; i++)
            for (int j = i; j >= 1; j--)
                for (int k = M - 1; k >= a[i]; k--)
                    f[j][k] = max(f[j][k], f[j - 1][k - a[i]] + b[i]);
        for (int i = 1; i <= n; i++)
        {
            double ans = 0;
            for (int j = 0; j < M; j++)
                ans = max(ans, min((tot_b + f[i][j]) / 2.0, 1.0 * j));
            cout << fixed << setprecision(1) << ans << " ";
        }
    }
    
  • 相关阅读:
    终端设备 tty,pty,pts 概念与文件描述符的联系
    Nginx – access_log格式及配置
    Nginx – rewrite 配置 URL重写及301跳转原理图
    nginx命令启动及选项
    nginx-web身份验证
    nginx_server_location对客户资源的辨别规则
    利用Session防止表单重复提交
    归并排序
    Cookie/Session的机制与安全
    HTTP Cookie Session
  • 原文地址:https://www.cnblogs.com/mollnn/p/14398107.html
Copyright © 2011-2022 走看看