CF730J Bottles
\(\mathtt{CF730J}\)
\(\mathcal{Description}\)
有 \(n\) 瓶水,每瓶水有两个值,剩下的水 \(a_i\) 和这瓶最大的容量 \(b_i\) \((a_i \leq b_i\)。现在要把所有水倒进其中几个瓶子中,是使用的瓶子数量最少。求出最少需要的瓶子和最小要用的时间\((\) 把 \(x\) 单元的水倒进另一个瓶子里需要\(x\) \()\)。
\(\mathcal{Solution}\)
第一问要求出最少需要的瓶子很简单,用贪心做,把 \(n\) 瓶水的最大容量排序,要使用的瓶子越大越好,第二问可以用 \(dp\) 做,\(dp[i][j]\) 可以表示选了 \(i\) 个瓶子,容量为 \(j\) 时,水的最大值。
\[dp[i][j] = max(dp[i][j], dp[i - 1][j - b[k]] + a[k])
\]
\(\mathcal{Code}\)
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n, sum, sum1, sum2, num, f[N][N * N];
struct Node {
int a, b;
} a[N];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline bool cmp (Node a, Node b) {
return a.b > b.b || (a.b == b.b && a.a > b.b);
}
int main() {
n = read();
for (int i = 1; i <= n; i++)
a[i].a = read(), sum += a[i].a;
for (int i = 1; i <= n; i++)
a[i].b = read(), sum1 += a[i].b;
std::sort(a + 1, a + 1 + n, cmp);
for (sum2 = sum; sum > 0; sum -= a[++num].b) ;
printf("%d ", num);
memset(f, -0x3f, sizeof(f));
f[0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = sum1; j >= a[i].b; j--)
for (int k = 1; k <= num; k++)
f[k][j] = std::max(f[k][j], f[k - 1][j - a[i].b] + a[i].a);
int ans = -1;
for (int i = sum2; i <= sum1; i++)
ans = std::max(ans, f[num][i]);
printf("%d\n", sum2 - ans);
return 0;
}