zoukankan      html  css  js  c++  java
  • bzoj1492

    斜率优化+cdq分治

    这个就是都不单调的情况

    dp[i] = max(a[i] * x[j] + b[i] * y[j])

    x[j] 表示能买多少a劵 y[j]表示能买多少b劵

    化简一下 dp[i] / b[i] = max(a[i] / b[i] * x[j] + y[j])

    非常标准的斜率优化形式 

    -(a[i] / b[i]) * x[j] + dp[i] / b[i] = y[j]

    可惜-(a[i] / b[i]) 和 y[j] 都不单调 那么我们就得用cdq分治和二分 然而二分可以通过排序优化掉

    我们先按-(a[i] / b[i]) 排序 

    然后cdq分治,每次先按编号分成两块 cdq左边

    现在左边的dp值已经得出 并且按照x[j] 排序

    那么我们可以直接左边构成凸包 因为右边还是-(a[i] / b[i]) 经过排序后单调 所以我们可以像普通斜率优化一样做一遍

    更新完之后我们再cdq右边

    最后两边按x归并

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 5;
    const double eps = 1e-9;
    int n, top;
    struct data {
        int id;
        double a, b, x, y, k, rate;
        bool friend operator < (const data &a, const data &b) {
            return a.k > b.k;
        }
    } a[N], t[N];
    double dp[N];
    int st[N];
    double slope(int i, int j)
    {
    //  if(!i || !j) return -1e20;
        if(fabs(a[i].x - a[j].x) < eps) return 1e20;
        return (a[i].y - a[j].y) / (a[i].x - a[j].x);
    }
    void cdq(int l, int r)
    {
        if(l == r) 
        {
            dp[l] = max(dp[l], dp[l - 1]);
            a[l].y = dp[l] / (a[l].a * a[l].rate + a[l].b);
            a[l].x = a[l].y * a[l].rate;
            return; 
        }
        int mid = (l + r) >> 1, p1 = l, p2 = mid + 1;
        for(int i = l; i <= r; ++i) if(a[i].id <= mid) t[p1++] = a[i]; else t[p2++] = a[i];
        for(int i = l; i <= r; ++i) a[i] = t[i];
        cdq(l, mid);
        top = 0;
        for(int i = l; i <= mid; ++i) 
        {
            while(top > 1 && slope(st[top], st[top - 1]) < slope(st[top], i) + eps) --top;
            st[++top] = i;
        }
        int j = 1;
    //  st[++top] = 0;
        for(int i = mid + 1; i <= r; ++i) 
        {
            while(j < top && slope(st[j], st[j + 1]) + eps > a[i].k) ++j;
            dp[a[i].id] = max(dp[a[i].id], a[st[j]].x * a[i].a + a[st[j]].y * a[i].b);
        } 
        cdq(mid + 1, r);
        int p = l;
        p1 = l;
        p2 = mid + 1;
        while(p1 <= mid && p2 <= r) if(a[p1].x < a[p2].x || (fabs(a[p1].x - a[p2].x) < eps && a[p1].y < a[p2].y)) t[p++] = a[p1++]; else t[p++] = a[p2++];
        while(p1 <= mid) t[p++] = a[p1++];
        while(p2 <= r) t[p++] = a[p2++];
        for(int i = l; i <= r; ++i) a[i] = t[i];
    }
    int main()
    {
    //  freopen("cash.in", "r", stdin);
    //  freopen("cash.out", "w", stdout);
        scanf("%d%lf", &n, &dp[0]);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%lf%lf%lf", &a[i].a, &a[i].b, &a[i].rate);
            a[i].k = -a[i].a / a[i].b;
            a[i].id = i;
        }
        sort(a + 1, a + n + 1);
        cdq(1, n);
    //  for(int i = 1; i <= n; ++i) printf("dp[%d] = %.3f
    ", i, dp[i]);
        printf("%.3f
    ", dp[n]);
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    View Code
  • 相关阅读:
    一个匪夷所思的错误
    String.Format 摘录
    DISTINCT的问题
    showModalDialog()、showModelessDialog()方法使用详解
    vbscript变量的特点
    vuecli3安装过程
    @vuecli3创建项目报错:ERROR command failed: npm install loglevel error registry=https://registry.npm.taobao.org di
    @vuecli3安装element组件过程
    dialogPostRun 覆盖方法class Dialog 动态创建
    清除重复记录只保留一条
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8284451.html
Copyright © 2011-2022 走看看