题意:
- 给定\(n\)个四元组,每个四元组用\((a_i,b_i,c_i,d_i)\)表示,且如果选了\(a_i\),则\(Q+=a_i,C+=b_i\),如果选了\(C_i\),则\(Q+=C_i,C+=d_i\).
- \(a_i\)至多选\(n_1\)个,\(c_i\)至多选\(n_2\)个,使\(Q/C\)尽量大.
- \(n_1+n_2\le n\le 500, Q_1,Q_2\le 2000, C_1,C_2\le 50\)
考虑二分答案\(t\).
则题目转化为求一个选择方案,使得\[\frac{\sum_{i\in S} a_i+\sum_{j\in T} c_j}{\sum_{i\in S} b_i+ \sum_{j\in T} d_j} \ge t\].
转化一下后其实是使\[\sum_{i\in S}a_i-b_i*t+\sum_{j\in T}c_j-d_j*t\],于是每个\(a_i\)变为\(a_i-b_i*t\),每个\(c_i\)变为\(c_i-d_i*t\).
于是按\(a_i-c_i\)排个序,随便DP一下就好.
这是典型的0/1规划题目。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ldb long double
#define L register int
#define F(i, a, b) for (L i = a; i <= b; i ++)
#define G(i, a, b) for (L i = a; i >= b; i --)
#define mx(a, b) ((a) = (a) > (b) ? (a) : (b))
#define Get getchar()
#define N 510
const ldb s = 1e-9;
using namespace std;
int n, n1, n2, Q1[N], C1[N], Q2[N], C2[N];
ldb a[N], b[N], f[N][N][2], g[N][N][2], ans, l, r, m, answer;
struct node{ ldb a, b, c; } d[N];
void R(L &x) {
char c = Get; x = 0; L t = 1;
for (; !isdigit(c); c = Get) t = (c == '-' ? - 1 : t);
for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = Get) ; x *= t;
}
bool cmp(node x, node y) { return x.c > y.c;
}
bool Good(ldb x) {
F(i, 1, n)
d[i].a = (ldb) Q1[i] - x * C1[i], d[i].b = (ldb) Q2[i] - x * C2[i], d[i].c = d[i].a - d[i].b;
sort(d + 1, d + n + 1, cmp), ans = -1e9;
F(i, 0, n + 1) F(j, 0, n + 1) f[i][j][0] = f[i][j][1] = g[i][j][0] = g[i][j][1] = -1e9;
f[0][0][0] = f[0][0][1] = g[n + 1][0][0] = g[n + 1][0][1] = 0;
F(i, 1, n)
F(j, 0, min(n1, i)) {
if (j) f[i][j][1] = max(f[i - 1][j - 1][1], f[i - 1][j - 1][0]) + d[i].a;
mx(f[i][j][0], f[i - 1][j][1]), mx(f[i][j][0], f[i - 1][j][0]);
}
G(i, n, 1)
F(j, 0, min(n2, n - i + 1)) {
if (j) g[i][j][1] = max(g[i + 1][j - 1][1], g[i + 1][j - 1][0]) + d[i].b;
mx(g[i][j][0], g[i + 1][j][1]), mx(g[i][j][0], g[i + 1][j][0]);
}
F(i, 1, n) {
mx(ans, f[i][n1][1] + g[i][n2][0]);
mx(ans, f[i][n1][0] + g[i][n2][1]);
}
return ans >= 0;
}
int main() {
freopen("love.in", "r", stdin) ;
freopen("love.out", "w", stdout) ;
R(n), R(n1), R(n2);
F(i, 1, n) R(Q1[i]), R(C1[i]), R(Q2[i]), R(C2[i]);
l = 0, r = 1000000;
while (l <= r) {
m = (l + r) / 2;
if (Good(m)) answer = m, l = m + s; else r = m - s;
}
printf("%Lf", answer);
}