[Bytedance]字节跳动2020网络赛J

赛时看了好久,思路一半对了但是没做出来,队友切了,现在赛后补题。

Codeforeces

题意:

有$n(\le 100)$个瓶子,每个瓶子有$a(\le 100)$容量和$b(\le 100)$的水,每次可以转移任意体积的水,但是转移的那部分水会少掉一半,同时如果瓶子满了,继续倒水就会浪费掉那部分。

现在要保留$k$个瓶子,其他扔掉。

求对于每个$k∈[1,n]$求最多剩下多少水。

思路:

考虑如果保留$k$个瓶子,瓶子集合为$S$,怎么倒水合理。

显然是其他的瓶子补满这部分瓶子的水就行了。

$ans = min{sum_{S_a}, sum_b  / 2+ sum_{S_b} / 2}$

其中$sum_b / 2$为常数

然后所有的$ans$取个max就是答案了

显然对于一个确定$sum_{S_a}$,$sum_{S_b}$越大越好

我们可以用背包,求出取$k$个瓶子,容量和为$A$的水量最大值

$f[i][k][A] = max{f[i - 1][k - 1][A - a[i]] + b[i]}$

可以利用01背包的方法滚掉第一维

注意$k$和$A$的枚举要倒序

 

 1 #include <bits/stdc++.h>
 2 #define int long long
 3 #define Mid ((l + r) >> 1)
 4 #define lson (rt << 1)
 5 #define rson (rt << 1 | 1)
 6 using namespace std;
 7 int read(){
 8     char c; int num, f = 1;
 9     while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
10     while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';;
11     return f * num;
12 }
13 int n, sum, sumb;
14 int a[109], b[109], ans;
15 int f[109][109 * 109];
16 main()
17 {
18     n = read();
19     memset(f, -1, sizeof(f));
20     f[0][0] = 0;
21     for(int i = 1; i <= n; i++) sum += (a[i] = read()), sumb += (b[i] = read());
22     for(int i = 1; i <= n; i++) {
23         for(int j = n; j; j--) {
24             for(int A = sum; A - a[i] >= 0; A--) if(f[j - 1][A - a[i]] != -1){
25                 f[j][A] = max(f[j][A], f[j - 1][A - a[i]] + b[i]);
26             }
27         }
28     }
29     double ans = 0;
30     for(int i = 1; i <= n; i++) {
31         ans = 0;
32         for(int A = 0; A <= sum; A++) if(f[i][A] != -1) {
33             ans = max(ans, min(f[i][A] / 2.0 + sumb / 2.0, A * 1.0));
34         }
35         printf("%lf\n", ans);
36     }
37     return 0;
38 }
View Code

 

posted @ 2020-12-22 22:41  _onglu  阅读(167)  评论(0编辑  收藏  举报