zoukankan      html  css  js  c++  java
  • 【BZOJ1492】【Luogu P4027】 [NOI2007]货币兑换 CDQ分治,平衡树,动态凸包

    斜率在转移顺序下不满足单调性的斜率优化(DP),用动态凸包来维护。送命题。

    简化版题意:每次在凸包上插入一个点,以及求一条斜率为(K)的直线与当前凸包的交点。思路简单实现困难。

    (P.s),不是特别建议用(Set)来维护动态凸包,万一中间哪一点功能实现(STL)没有提供就(GG)了。(比如要有两种比较运算符。)本人因此重构了三次(:))

    代码来源:黄学长的代码的魔改版。

    #include <bits/stdc++.h>
    using namespace std;
    
    const double eps = 1e-8;
    const int N = 100000 + 5;
    
    int n, top, sta[N]; double f[N];
    
    struct point {
    	double x, y, a, b, k, rate; int w, id;
    }p[N], t[N];
    
    double getk (int a, int b) {
    	if (b == 0) return -1e20;
    	if (fabs (p[a].x - p[b].x) < eps) {
    		return 1e20;
    	} else {
    		return (p[b].y - p[a].y) / (p[b].x - p[a].x);
    	}
    }
    
    bool operator < (point a, point b) {
    	return a.k > b.k;
    }
    
    void solve (int l, int r) {
    	if (l == r) {
    		f[l] = max (f[l], f[l - 1]);
    		p[l].y = f[l] / (p[l].a * p[l].rate + p[l].b);
    		p[l].x = p[l].rate * p[l].y;
    		return;
    	}//分治到底了显然我们可以直接计算出结果 
    	int l1, l2, mid = (l + r) >> 1, j = 1;
    //============================================================================
    	l1 = l; l2 = mid + 1;
    	for (int i = l; i <= r; i++) {
    	    if (p[i].id <= mid) {
    			t[l1++] = p[i];
    		} else {
    			t[l2++] = p[i];
    		}
    	}
        for (int i = l; i <= r; i++) {
    		p[i] = t[i];
    	}
    	solve (l, mid);//递归左边
    	top = 0;
    	for (int i = l; i <= mid; i++) {
    		while (top > 1 && getk (sta[top - 1], sta[top]) < getk (sta[top - 1], i) + eps) {
    		    top--;
    		}
    		sta[++top] = i;
        }//左边维护一个凸包
        sta[++top] = 0;
        for (int i = mid + 1; i <= r; i++) {
        	while (j < top && getk (sta[j], sta[j + 1]) + eps > p[i].k) {
    			j++;
    		}//用左边的点作为决策更新右边 
            f[p[i].id] = max (f[p[i].id], p[sta[j]].x * p[i].a + p[sta[j]].y * p[i].b);
    	}
    	solve (mid + 1, r);//递归右边 
    	l1 = l; l2 = mid + 1;
    	for (int i = l; i <= r; i++) {
    		if (((p[l1].x < p[l2].x || (fabs(p[l1].x - p[l2].x) < eps && p[l1].y < p[l2].y)) || l2 > r) && l1 <= mid) {
    			t[i] = p[l1++];
    		} else {
    			t[i] = p[l2++];
    		}
    	}
        for (int i = l; i <= r; i++) p[i] = t[i];
    }
    
    int main () {
    //	freopen ("data.in", "r", stdin);
    	cin >> n >> f[0];
    	for (int i = 1; i <= n; i++) {
    		cin >> p[i].a >> p[i].b >> p[i].rate;
    		p[i].k = -p[i].a / p[i].b; p[i].id = i;
    	}
    	sort (p + 1, p + n + 1);//这里按照斜率进行排序,保证分治的每一块斜率是有序的 
    	solve (1, n);
    	cout << fixed << setprecision (10) << f[n] << endl;
    }
    
  • 相关阅读:
    vue学习笔记之v-if
    vue学习笔记之属性和方法
    vue学习笔记之v-for与-repeat
    王阳明心学
    读《铁血并购》
    心理测试:DISC性格测试(完整版)
    关于旅行
    [转载]win32 计时器使用
    [转]C#中调用资源管理器(Explorer.exe)打开指定文件夹 + 并选中指定文件 + 调用(系统默认的播放类)软件(如WMP)打开(播放歌曲等)文件
    [转]C#读写TEXT文件
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10931211.html
Copyright © 2011-2022 走看看