zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    C++_学习随笔_牛郎织女迷宫
    UE4复习5_蓝图接口简单应用
    UE4复习4_射线检测
    今日份学习: Spring中使用AOP并实现redis缓存?
    动态代理,AOP和Spring
    今日份学习:初步的springboot
    HTML常用标签
    关于类的笔记
    关于编码的一个笔记
    Java Socket例程3 UDP
  • 原文地址:https://www.cnblogs.com/tuchen/p/14155944.html
Copyright © 2011-2022 走看看