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
  • 相关阅读:
    毕业进度10
    毕业进度9
    毕业进度8
    毕业设计7
    毕业设计6
    java算法每日一练2021/1/26
    java算法每日一练2021/1/23
    java算法每日一练2021/1/21
    java算法每日一练2021/1/20
    java算法每日一练2021-01-18
  • 原文地址:https://www.cnblogs.com/Colythme/p/10150404.html
Copyright © 2011-2022 走看看