zoukankan      html  css  js  c++  java
  • 【做题】arc072_f-Dam——维护下凸包

    题意:有一个容量为(L)的水库,每天晚上可以放任意体积的水。每天早上会有一定温度和体积的水流入水库,且要保证流入水之后水的总体积不能超过(L)。令体积分别为(V_1,V_2),温度分别为(t_1,t_2)的水混合后的温度为(frac {V_1 * t_1 + V_2 * t_2} {V_1 + V_2})。初始水库为空。现给出(n)天流入水的体积和温度,分别最大化每一天中午水库满容量时的水温。
    (n <= 500000, space L,t <= 10^9,space V <= L)

    显然记录水温时直接记录温度和体积的乘积,这样混合时直接相加就可以了。这个混合满足结合律。
    那么,我们可以把水表示为二维平面上的向量,(x)坐标为体积,(y)坐标为温度和体积的乘积。那么,温度就等于它的斜率。我们贪心一下,如果新加入的水导致水温下降,那么一定会在新加入水后再排水。否则,便可以在新加入水之前排水。这启发我们维护一个下凸包。如果某一天晚上是可以排水的,那么就不先与后面的水混合。否则便把两个向量相加。具体排水时放出斜率较小的水,流入水时不断与现有的水合并直到斜率大于之前的水为止。最大化第(i+1)天水的温度,就是最大化第(i)天放水后的水温,故我们直接从第(i)天的决策更新到第(i+1)天的决策,还可以保证新的决策时刻满足水的体积不超过(L)
    时间复杂度(O(n))

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 500010;
    typedef double db;
    const db eps = 1e-8;
    inline int judge(db x) {
      return x > -eps ? x > eps ? 1 : 0 : -1;
    }
    struct point {
      db x,y;
      point(db x_=0,db y_=0): x(x_), y(y_) {}
      db operator * (const point& a) const {
        return x * a.y - y * a.x;
      }
      point operator + (const point& a) const {
        return point(x + a.x, y + a.y);
      }
      point operator - (const point& a) const {
        return point(x - a.x, y - a.y);
      }
      void operator += (const point& a) {
        *this = *this + a;
      }
      void operator -= (const point& a) {
        *this = *this - a;
      }
    } q[N];
    int n,cap,t,v,l=1,r;
    point cur,tmp;
    int main() {
      scanf("%d%d",&n,&cap);
      scanf("%d%d",&t,&v);
      printf("%d.00000000
    ",t);
      q[++r] = point(v,1.0 * t * v);
      cur += point(v,1.0 * t * v);
      for (int i = 2 ; i <= n ; ++ i) {
        scanf("%d%d",&t,&v);
        db a = v;
        while (judge(a - q[l].x) >= 0)
          a -= q[l].x, cur -= q[l++];
        cur -= q[l];
        q[l].y *= (q[l].x - a) / q[l].x;
        q[l].x -= a;
        cur += q[l];
        tmp = point(v,1.0 * t * v);
        while (l <= r && judge(q[r] * tmp) <= 0)
          tmp += q[r], cur -= q[r--];
        if (judge(tmp.x - cap) > 0) {
          tmp.y *= cap / tmp.x;
          tmp.x = cap;
        }
        q[++r] = tmp;
        cur += tmp;
        printf("%.8lf
    ",cur.y / cur.x);
      }
      return 0;
    }
    

    小结:在贪心的基础上维护下凸包(或单调队列),从而容易转移。感觉自己做起来还有难度。
  • 相关阅读:
    MySql 有用的函数
    mysql 触发器
    java之switch语句
    MaxAlertView 强大的弹框试图
    AVMoviePlayer 视频播放器
    Mac下不能安装第三方下载软件
    HTTPS链式编程——AFNetworking 3.0
    iOS推送证书生成pem文件(详细步骤)
    iOS成长之路-使用系统默认声音、震动
    iOS 怎么自定制推送声音呢?(APP运行时和APP进入后台时)
  • 原文地址:https://www.cnblogs.com/cly-none/p/9205674.html
Copyright © 2011-2022 走看看