zoukankan      html  css  js  c++  java
  • CF739E Gosha is hunting DP+wqs二分

    我是从其他博客里看到这题的,上面说做法是wqs二分套wqs二分?但是我好懒呀,只用了一个wqs二分,于是(O(nlog^2n))(O(n^2logn))
    首先我们有一个(O(n^3))的暴力(DP),转移好写,形式优美,但复杂度不对
    该怎样发现它的凸性质呢
    1.打表√
    2.冷静分析一波,每一种球肯定是越多越好,于是我们先固定选择(a)个普通球,然后那(b)个大师球肯定是从大到小挑选。这样的话每多选一个,新增的收益就会下降一点,也就是说这是个上凸函数。(口胡如果假的话,就锤我吧)√
    然后就可以用wqs二分干掉一维啦,设(f[i][j])表示考虑到第(i)只精灵,已经选了(j)个普通球和若干个大师球时的最大期望,二分一个斜率(mid),每次check时转移一下(f)数组,拿最优决策点和(b)比较来调整范围
    细节就是如果有多个相同的(f)值,取大师球最多的
    代码如下:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    //暴力DP:n^3
    //wqs二分:n^2logn
    
    #define N 2000
    const double eps = 1e-8; //我1e-6的精度被卡掉了。。。
    
    int n, a, b;
    double p[N+5], u[N+5], mid;
    double sum;
    int cnt;
    
    bool dcmp(double x, double y) {
      return fabs(x-y) <= eps;
    };
    
    struct Data {
      double v;
      int cnt;
      bool operator < (const Data &rhs) const { //方便
        return dcmp(v, rhs.v) ? cnt < rhs.cnt : v < rhs.v;
      }
    }f[N+5][N+5], opt;
    
    Data newData(Data &d, double v, int cnt) {
      return Data{d.v+v, d.cnt+cnt};
    }
    
    void check() {
      for(int i = 1; i <= n; ++i) {
        for(int j = 0; j <= a; ++j) {
          //分类讨论转移
          //1.什么都不选
          //2.只选p
          //3.只选u
          //4.两个都选
          //取max
          f[i][j] = f[i-1][j];
          if(j >= 1) f[i][j] = max(f[i][j], newData(f[i-1][j-1], p[i], 0)); //记得减掉附加权值
          f[i][j] = max(f[i][j], newData(f[i-1][j], u[i]-mid, 1));
          if(j >= 1) f[i][j] = max(f[i][j], newData(f[i-1][j-1], p[i]+u[i]-p[i]*u[i]-mid, 1));
        }
      }
      opt = f[n][a];
    }
    
    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", &u[i]);
      double l = 0, r = 1, slope = r;
      while(fabs(r-l) > eps) { //二分斜率
        mid = (l+r)*0.5;
        check();
        if(opt.cnt >= b) l = mid, slope = mid;
        else r = mid;
      }
      mid = slope;
      check();
      printf("%.5lf
    ", opt.v+b*slope);
      return 0;
    }
    
  • 相关阅读:
    [Java]如何把当前时间插入到数据库
    [Java]Get与Post,客户端跳转与服务器端跳转
    [Java]MyBatis框架
    [Java]Java分层概念(转)
    [Java]Spring框架
    [Java]JavaScript在这里学习
    [Java]Servlet&JSP
    [Java]jdbc[转]
    [工具]GitHub上整理的一些工具[转]
    [Java] 集合框架
  • 原文地址:https://www.cnblogs.com/dummyummy/p/10578946.html
Copyright © 2011-2022 走看看