zoukankan      html  css  js  c++  java
  • [NOI2007]货币兑换 「CDQ分治实现斜率优化」

    首先每次买卖一定是在某天 $k$ 以当时的最大收入买入,再到第 $i$ 天卖出,那么易得方程:

    $$f_i = max {frac{A_iRate_kf_k}{A_kRate_k + B_k} + frac{B_if_k}{A_kRate_k + B_k}}$$

    再令

    $$left{egin{aligned} x_k = frac{Rate_kf_k}{A_kRate_k + B_k} \ y_k = frac{f_k}{A_kRate_k + B_k}end{aligned} ight.$$

    则有

    $$egin{aligned} f_i &= max {A_ix_k + B_iy_k} \ y_k &= - frac{A_i}{B_i}x_k + frac{f_i}{B_i} end{aligned}$$

    那么现在需要找到一个点 $(x_k, y_k)$ 使得直线的截距最大

    由于斜率和横坐标皆不满足单调性,可以用平衡树等维护,这里使用CDQ分治实现

    实现过程如下:

    Ⅰ 将数据按照斜率$frac{A_i}{B_i}$降序排序

    Ⅱ 将区间按照操作顺序分为左右两部分处理

    Ⅲ 先处理左半部分,维护左半边凸包(注意,此时左半边已按照 $x$ 排序)

    Ⅳ 处理左半边对右半边的影响,由于已按照斜率降序排序,所以普通斜率优化即可

    Ⅴ 将区间按照 $x$ 排序

    代码

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <cmath>
      6 
      7 using namespace std;
      8 
      9 const int MAXN = 1e05 + 10;
     10 
     11 const double INF = 1e60;
     12 const double eps = 1e-08;
     13 
     14 int Dcmp (double p) {
     15     if (fabs (p) < eps)
     16         return 0;
     17     return p < 0 ? - 1 : 1;
     18 }
     19 
     20 struct CashSt {
     21     double a, b, rate;
     22     double k, x, y;
     23     int index;
     24 
     25     CashSt () {}
     26 
     27     bool operator < (const CashSt& p) const {
     28         return Dcmp (x - p.x) == 0 ? Dcmp (y - p.y) < 0 : Dcmp (x - p.x) < 0;
     29     }
     30 } ;
     31 CashSt Cash[MAXN];
     32 bool comp (const CashSt& a, const CashSt& b) {
     33     return Dcmp (a.k - b.k) > 0;
     34 }
     35 
     36 int N;
     37 
     38 double slope (CashSt a, CashSt b) {
     39     if (Dcmp (b.x - a.x) == 0)
     40         return INF;
     41     return (b.y - a.y) / (b.x - a.x);
     42 }
     43 double f[MAXN]= {0};
     44 CashSt Que[MAXN];
     45 int l = 1, r = 0;
     46 CashSt temp[MAXN];
     47 void CDQ (int left, int right) {
     48     if (left == right) {
     49         f[left] = max (f[left], f[left - 1]);
     50         Cash[left].y = f[left] / (Cash[left].a * Cash[left].rate + Cash[left].b);
     51         Cash[left].x = Cash[left].y * Cash[left].rate;
     52         return ;
     53     }
     54     int mid = (left + right) >> 1;
     55     int p1 = left - 1, p2 = mid;
     56     for (int i = left; i <= right; i ++)
     57         Cash[i].index <= mid ? temp[++ p1] = Cash[i] : temp[++ p2] = Cash[i];
     58     for (int i = left; i <= right; i ++)
     59         Cash[i] = temp[i];
     60     CDQ (left, mid);
     61     l = 1, r = 0;
     62     for (int i = left; i <= mid; i ++) {
     63         while (l < r && Dcmp (slope (Que[r - 1], Que[r]) - slope (Que[r], Cash[i])) < 0)
     64             r --;
     65         Que[++ r] = Cash[i];
     66     }
     67     for (int i = mid + 1; i <= right; i ++) {
     68         while (l < r && Dcmp (slope (Que[l], Que[l + 1]) - Cash[i].k) > 0)
     69             l ++;
     70         f[Cash[i].index] = max (f[Cash[i].index], Cash[i].a * Que[l].x + Cash[i].b * Que[l].y);
     71     }
     72     CDQ (mid + 1, right);
     73     l = left, r = mid + 1;
     74     int p = 0;
     75     while (l <= mid && r <= right) {
     76         // if (Dcmp (Cash[l].x - Cash[r].x) < 0 || (Dcmp (Cash[l].x - Cash[r].x) == 0 && Dcmp (Cash[l].y - Cash[r].y) < 0))
     77         if (Cash[l] < Cash[r])
     78             temp[++ p] = Cash[l], l ++;
     79         else
     80             temp[++ p] = Cash[r], r ++;
     81     }
     82     while (l <= mid)
     83         temp[++ p] = Cash[l], l ++;
     84     while (r <= right)
     85         temp[++ p] = Cash[r], r ++;
     86     for (int i = 1; i <= p; i ++)
     87         Cash[i + left - 1] = temp[i];
     88 }
     89 
     90 double getnum () {
     91     double num = 0.0;
     92     char ch = getchar ();
     93     double T = 1.0;
     94 
     95     while (! isdigit (ch))
     96         ch = getchar ();
     97     while (isdigit (ch))
     98         num = num * 10.0 + (ch - '0') * 1.0, ch = getchar ();
     99     if (ch == '.') {
    100         ch = getchar ();
    101         while (isdigit (ch))
    102             num = num + (T /= 10.0) * (ch - '0'), ch = getchar ();
    103     }
    104 
    105     return num;
    106 }
    107 
    108 int main () {
    109     // freopen ("Input.txt", "r", stdin);
    110 
    111     scanf ("%d%lf", & N, & f[0]);
    112     for (int i = 1; i <= N; i ++) {
    113         double a = getnum (), b = getnum (), rate = getnum ();
    114         Cash[i].a = a, Cash[i].b = b, Cash[i].rate = rate;
    115         Cash[i].index = i;
    116         Cash[i].k = - a / b;
    117     }
    118     sort (Cash + 1, Cash + N + 1, comp);
    119     CDQ (1, N);
    120     printf ("%.3f
    ", f[N]);
    121 
    122     return 0;
    123 }
    124 
    125 /*
    126 3 100
    127 1 1 1
    128 1 2 2
    129 2 2 3
    130 */
    View Code
  • 相关阅读:
    win10 UWP button
    内网分享资源
    内网分享资源
    CF724F Uniformly Branched Trees
    win10 UWP FlipView
    win10 UWP FlipView
    win10 UWP FlipView
    搭建阿里云 centos mysql tomcat jdk
    搭建阿里云 centos mysql tomcat jdk
    win10 UWP 申请微软开发者
  • 原文地址:https://www.cnblogs.com/Colythme/p/10150404.html
Copyright © 2011-2022 走看看