DP 做法
首先暴力 n ^ 3的DP应该没有问题, 但是空间和时间都压不下来, 于是有了凸优化
表示第 i 位, 用了j个宝贝球, k个超级球
现在变成 表示第 i 位, 用了j个宝贝球, 随便用多少个超级球的最优方案
如果我们选出来的超级球大于b个, 那么我们将每个超级球的值减小 k , 这样选出来的可能会少一些
我们二分这个k, 直到选出来的超级球恰好为 b
同理, 将 j 一维也优化掉, 复杂度 O(n log^2)
费用流做法
首先原点向 A 连流量为 a 的边, 表示最多 a 个宝贝球, 先 B 连流量为 b 的边
然后 a 先每个 i 连 流量为1, 费用为 p[i] 的边, b 向 i 连流量为1, 费用为v[i] 的边
然后每个点向终点连流量为 1 的边
等等, 两个都选呢 ? 此时到 i 的流量为2, 有1会通过费用为0的边到终点
我们把选两个的式子拆开, 发现需要减去 p[i] * v[i], 于是每个i再向原点连费用为 - p[i] * v[i], 流量为1 的边
#include<bits/stdc++.h>
#define N 2005
using namespace std;
const double eps = 1e-12;
int n, a, b;
double f[N], p[N], v[N]; int cnta[N], cntb[N];
void calc(double dx, double dy){
for(int i=0; i<=n; i++) f[i] = cnta[i] = cntb[i] = 0;
for(int i=1; i<=n; i++){
f[i] = f[i-1]; cnta[i] = cnta[i-1]; cntb[i] = cntb[i-1];
if(f[i-1] + p[i] > f[i] + dx) f[i] = f[i-1] + p[i] - dx, cnta[i] = cnta[i-1] + 1, cntb[i] = cntb[i-1];
if(f[i-1] + v[i] > f[i] + dy) f[i] = f[i-1] + v[i] - dy, cnta[i] = cnta[i-1], cntb[i] = cntb[i-1] + 1;
if(f[i-1] + (1 - (1 - p[i]) * (1 - v[i])) > f[i] + dx + dy)
f[i] = f[i-1] + (1 - (1 - p[i]) * (1 - v[i])) - dx - dy,
cnta[i] = cnta[i-1] + 1, cntb[i] = cntb[i-1] + 1;
}
}
int main(){
scanf("%d%d%d", &n, &a, &b);
for(int i=1; i<=n; i++) scanf("%lf", &p[i]);
for(int i=1; i<=n; i++) scanf("%lf", &v[i]);
double l = 0, r = 1, L, R;
while(r - l > eps){
double mid = (l+r) / 2;
L = 0, R = 1;
while(R - L > eps){
double Mid = (L+R) / 2;
calc(mid, Mid);
if(cntb[n] > b) L = Mid; else R = Mid;
}
calc(mid, R);
if(cnta[n] > a) l = mid; else r = mid;
} calc(r, R);
printf("%.5lf", f[n] + a * r + b * R);
return 0;
}
#include<bits/stdc++.h>
#define N 100050
using namespace std;
const double eps = 1e-10;
int first[N], nxt[N], to[N], w[N], tot = 1; double c[N];
void add(int x, int y, int z, double v){
nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z, c[tot] = v;
nxt[++tot] = first[y], first[y] = tot, to[tot] = x, w[tot] = 0, c[tot] = -v;
}
int n, a, b; double p[N], v[N];
int st, ed, A, B;
double dis[N]; bool vis[N];
int from[N], froms[N];
bool spfa(){
for(int i=0; i<=n+3; i++) dis[i] = 1e9, vis[i] = 0;
queue<int> q; q.push(st); vis[st] = 1; dis[st] = 0;
while(!q.empty()){
int x = q.front(); q.pop(); vis[x] = 0;
for(int i=first[x];i;i=nxt[i]){
int t = to[i];
if(w[i] && dis[x] + c[i] + eps < dis[t]){
dis[t] = dis[x] + c[i]; from[t] = x; froms[t] = i;
if(!vis[t]) q.push(t), vis[t] = 1;
}
}
} return dis[ed] < 1e9;
}
int calc(){
int u = ed, flow = 0x3fffffff;
while(u){ flow = min(flow, w[froms[u]]); u = from[u];} u = ed;
while(u){ w[froms[u]] -= flow; w[froms[u] ^ 1] += flow; u = from[u];}
return flow;
}
double dinic(){ double ans = 0; while(spfa()) ans += dis[ed] * calc(); return ans;}
int main(){
scanf("%d%d%d", &n, &a, &b);
for(int i=1; i<=n; i++) scanf("%lf", &p[i]);
for(int i=1; i<=n; i++) scanf("%lf", &v[i]);
st = 0; ed = n + 1; A = n + 2; B = n + 3;
add(st, A, a, 0); add(st, B, b, 0);
for(int i=1; i<=n; i++){
add(A, i, 1, -p[i]); add(B, i, 1, -v[i]);
add(i, ed, 1, 0); add(i, ed, 1, p[i] * v[i]);
} printf("%.4lf", -dinic());
return 0;
}