codeforces 739 E. Gosha is hunting (dp + 凸优化)

题目链接:https://codeforces.com/contest/739/problem/E

凸优化经典题

凸优化:

指有若干个物品,要求选出 (m) 个,选的时候带有限制,求最优的方案。

这种题的特点是:如果不限制选的个数,很容易就能求出最优方案。

使用凸优化的条件:设 (f(i)) 为选 (i) 个物品的最优方案,则 (f(i)) 是关于 (i) 的凸函数

对于该题:很容易想到 (O(n^3))(dp), (dp[i][j][k]) 表示捕捉前 (i) 个精灵,用了 (j) 个宝贝球,(k) 个超级球的最大期望
转移讨论四种情况即可

可以发现,(j,k) 两维都是凸的,即选的越多期望越大,于是两维都可以使用凸优化

时间复杂度 (O(nlog^2n))

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;

const int maxn = 2010;
const double eps = 1e-8;

int n, a, b;
double p[maxn], u[maxn];
double dp[maxn][maxn];
int g[maxn][maxn];

bool check(double x){
	memset(dp, 0, sizeof(dp));
	memset(g, 0, sizeof(g));
	
	for(int i = 1 ; i <= n ; ++i){
		for(int j = 0 ; j <= a ; ++j){
			dp[i][j] = max(dp[i][j], dp[i-1][j]);
			g[i][j] = g[i-1][j];
			if(j >= 1){
				if(dp[i-1][j-1] + p[i] - dp[i][j] > eps){
					dp[i][j] = max(dp[i][j], dp[i-1][j-1] + p[i]);
					g[i][j] = g[i-1][j-1];
				}
			}
			if(dp[i-1][j] + u[i] - x - dp[i][j] > eps){
				dp[i][j] = max(dp[i][j], dp[i-1][j] + u[i] - x);
				g[i][j] = g[i-1][j] + 1;
			}
			if(j >= 1) {
				if(dp[i-1][j-1] + p[i] + u[i] - u[i] * p[i] - x - dp[i][j] > eps){
					dp[i][j] = max(dp[i][j], dp[i-1][j-1] + p[i] + u[i] - u[i] * p[i] - x);
					g[i][j] = g[i-1][j-1] + 1;
				}	
			}
		}
	}
	
	if(g[n][a] >= b) return true;
	else return false;
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read(), a = read(), b = read();
	for(int i = 1 ; i <= n ; ++i) scanf("%lf", &p[i]);
	for(int i = 1 ; i <= n ; ++i) scanf("%lf", &u[i]);
	
	double l = 0, r = 1;
	while(r - l > eps){
		double mid = (l + r) / 2;
		if(check(mid)) l = mid;
		else r = mid;
	}
	
	printf("%.3lf
", dp[n][a] + b * l);
	
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/14155944.html