题解:P7801 [COCI 2015/2016 #6] KRUMPIRKO
P7801 [COCI 2015/2016 #6] KRUMPIRKO
Tag:DP
考虑能不能直接 DP,发现不好计算。
发现答案是分数的形式,考虑 01分数规划,但分子分母并不是关于
首先这个题目的答案有两个未知数,不太好处理,我们把它变换为:
其中
现在还有一个问题,我们不能和平常一样,固定一些已经选出的物品,然后考虑新增的物品,因为这样取
这时候你会发现题目还有一个性质没用上:
我们直接枚举
于是现在问题就转换为:求选择
这个可以直接 DP,设
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using UI = unsigned int;
using ULL = unsigned long long;
using DB = double;
using LDB = long double;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
#define CP(x) complex<x>
#define fst first
#define snd second
#define popcnt(i) __builtin_popcount(i)
const int N = 1e2 + 5, V = 5e2 + 5;
const LL INF = 2e18;
int n, m;
LL suma, sumb, a[N], b[N], f[2][N][V], g[2][N][V];
// f: max, g: min
LDB val(LL sa, LL sb) {
if (sb == INF || sb == -INF) return INF;
return (DB)(sumb - sb) * sb / ((suma - sa) * sa);
}
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
suma += a[i];
}
for (int i = 1; i <= n; i++) {
scanf("%lld", &b[i]);
sumb += b[i];
}
int cur = 0;
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= suma; j++) {
f[0][i][j] = -INF;
g[0][i][j] = INF;
}
}
f[0][0][0] = g[0][0][0] = 0;
for (int i = 1; i <= n; i++) {
cur ^= 1;
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= suma; k++) {
f[cur][j][k] = f[cur ^ 1][j][k];
if (j && k >= a[i] && f[cur ^ 1][j - 1][k - a[i]] != -INF) {
f[cur][j][k] = max(f[cur][j][k], f[cur ^ 1][j - 1][k - a[i]] + b[i]);
}
g[cur][j][k] = g[cur ^ 1][j][k];
if (j && k >= a[i] && g[cur ^ 1][j - 1][k - a[i]] != INF) {
g[cur][j][k] = min(g[cur][j][k], g[cur ^ 1][j - 1][k - a[i]] + b[i]);
}
}
}
}
LDB ans = INF;
for (int i = 0; i <= suma; i++) {
ans = min({ans, val(i, f[cur][m][i]), val(i, g[cur][m][i])});
}
printf("%.3Lf\n", ans);
}
int main() {
solve();
return 0;
}