• bzoj-1492 货币兑换Cash (1)——平衡树维护凸包


    题意:

    有n天和m的初始金钱,用来购买AB两种纪念券;

    n天里每天都有AB的价格。每天能够进行这种操作。

    1.卖出手中x%的纪念券(AB分别都卖出x%)。

    2.用x的金钱买入纪念券。买入AB券的比例在第i天为Rate i;

    求n天过去之后所获得的最大收益。

    金钱和券数均为实数;

    n<=100 000;


    题解:

    首先,尽管题中的买入和卖出都是随意数量的。可是相同的纪念券,分几天卖出得到的收 益。一定小于等于直接在一天卖出的收益;

    相同。分几天买入也是不如一天花全部钱买入的;

    令:

    f[i]为第i天的最大收益。

    X[i]为第i天将全部钱数都买入得到的A券数。

    Y[i]为第i天将全部钱数都买入得到的B券数;

    显然X,Y都能够由f[i]得来。

    那么转移方程就是:

    f[i]=max(f[i-1],A[i] * X[j] + B[i] * Y[j]);(1<=j< i);

    这样转移是O(n^2)的。所以要对后面枚举j的部分优化;

    将f[i]=A[i] * X[j] + B[i] * Y[j]整理;

    得到Y[i]=(-A[i]/B[i]) * X[i] + f[i]/B[i];

    这是一个直线方程的形式,而对于固定的i,直线斜率不变,而要最大化截距;

    倘若将全部的[1,i-1]的点计算出(x,y)放在坐标系上;

    找到最优值相当于在这个上凸包上找到某个点。使截距最大。

    那么这个点左面的斜率一定大于当前i的斜率,右面的斜率一定小于当前i的斜率。

    所以这事实上就是一个斜率优化的形式;

    通常我们做斜率优化都是找到不符合要求的点直接干掉就好的;

    由于下一个i的斜率不是递增就是递减;

    可是这个-A[i]/B[i]不单调,所以不能O(n)的维护队列处理凸包;

    10^5的复杂度是支持O(nlogn)的,所以为了维护凸包能够选择一些数据结构;

    那么就维护一个Splay,每一个结点都在凸包上,中序遍历就是按x递增同一时候也按斜率递减的序列;

    假设把Splay看做logn,那么每一个点最多进出凸包一次。二分查询斜率共n次。

    复杂度O(nlogn)还是听起来非常好的;

    可是写起来一点也不好玩!

    总之维护凸包时对Splay中点较少时的讨论非常烦。。。

    照着对拍调数据改改也就过了。

    代码3k+,时间960ms,这个跑的感觉也是挺快的了;

    下一篇写写更神的CDQ分治,毕竟数据结构对代码能力要求颇高。

    7/17

    我被D了。。

    。斜率打成了shope,恩应该是slope无误;


    代码:


    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 110000
    #define which(x)	(tr[tr[x].fa].ch[1]==x)
    const double INF = 1e100;
    const double EPS = 1e-8;
    using namespace std;
    struct Point
    {
    	double x, y, s1, s2;
    	int fa, ch[2];
    }tr[N];
    int root, tot;
    double f[N], A[N], B[N], R[N], X[N], Y[N];
    void get_slope(int a, int b)
    {
    	if (!a)			tr[b].s1 = INF;
    	else if (!b)		tr[a].s2 = -INF;
    	else
    	{
    		if (fabs(tr[a].x - tr[b].x)<EPS)
    			tr[a].s2 = tr[b].s1 = (tr[a].y<tr[b].y ? INF : -INF);
    		else
    			tr[a].s2 = tr[b].s1 = (tr[a].y - tr[b].y) / (tr[a].x - tr[b].x);
    	}
    }
    void Rotate(int x)
    {
    	int f = tr[x].fa;
    	if (!f)	return;
    	bool k = which(x);
    	tr[f].ch[k] = tr[x].ch[!k];
    	tr[x].ch[!k] = f;
    	tr[tr[f].fa].ch[which(f)] = x;
    	tr[x].fa = tr[f].fa;
    	tr[tr[f].ch[k]].fa = f;
    	tr[f].fa = x;
    }
    void Splay(int x, int g)
    {
    	if (!x)	return;
    	while (tr[x].fa != g)
    	{
    		int f = tr[x].fa;
    		if (tr[f].fa == g)
    		{
    			Rotate(x);
    			break;
    		}
    		if (which(x) ^ which(f))
    			Rotate(x);
    		else
    			Rotate(f);
    		Rotate(x);
    	}
    	if (!g)	root = x;
    }
    int Pre(int x)
    {
    	if (!x)	return 0;
    	int p = tr[x].ch[0];
    	if (!p)	return 0;
    	while (tr[p].ch[1])
    		p = tr[p].ch[1];
    	return p;
    }
    int Sub(int x)
    {
    	if (!x)	return 0;
    	int p = tr[x].ch[1];
    	if (!p)	return 0;
    	while (tr[p].ch[0])
    		p = tr[p].ch[0];
    	return p;
    }
    int find(int p, double x)
    {
    	if (!p)	return 0;
    	if (x<tr[p].x)
    		return find(tr[p].ch[0], x);
    	else
    	{
    		int t = find(tr[p].ch[1], x);
    		return tr[p].x>tr[t].x ?

    p : t; } } void Insert(double X, double Y, int no) { int x = find(root, X), y = 0; if (!x) { x = root; while (tr[x].ch[0]) x = tr[x].ch[0]; Splay(x, 0); y = x, x = 0; } else { Splay(x, 0); Splay(y = Sub(x), x); } tr[no].x = X, tr[no].y = Y; if (y) tr[no].fa = y, tr[y].ch[0] = no; else tr[no].fa = x, tr[x].ch[1] = no; get_slope(x, no); get_slope(no, y); if (tr[no].s1 <= tr[no].s2) { tr[y].ch[0] = 0; get_slope(x, y); return; } Rotate(no), Rotate(no); root = no; x = tr[no].ch[0]; while (tr[x].s1 <= tr[x].s2&&x) { y = Pre(x); Splay(y, x); tr[y].fa = no; tr[no].ch[0] = y; get_slope(y, no); x = y; } x = tr[no].ch[1]; while (tr[x].s1 <= tr[x].s2&&x) { y = Sub(x); Splay(y, x); tr[y].fa = no; tr[no].ch[1] = y; get_slope(no, y); x = y; } } int query(double S) { int p = root; while (S>tr[p].s1 || S<tr[p].s2) { if (S>tr[p].s1) p = tr[p].ch[0]; else p = tr[p].ch[1]; } return p; } int main() { int n, i, j, k; scanf("%d%lf", &n, &f[1]); for (i = 1; i <= n; i++) scanf("%lf%lf%lf", A + i, B + i, R + i); tr[0].x = tr[0].y = -INF; Y[1] = f[1] / (A[1] * R[1] + B[1]); X[1] = R[1] * Y[1]; Insert(X[1], Y[1], 1); for (i = 2; i <= n; i++) { j = query(-A[i] / B[i]); f[i] = max(f[i - 1], A[i] * X[j] + B[i] * Y[j]); Y[i] = f[i] / (A[i] * R[i] + B[i]); X[i] = R[i] * Y[i]; Insert(X[i], Y[i], i); } printf("%.3lf", f[n]); return 0; }



  • 相关阅读:
    【常用】source insight常用设置及快捷键
    【Linux学习】配置环境:实现【VirtualBox + ubuntu】+【开启ssh服务】+【putty远程连接到虚拟机】
    javascript:区别浏览器
    linux 之centos6.3 安装中文输入法
    前端优化(静态资源)
    javascript 学习心得!
    编程总结
    2019年春季学期第二周作业
    HTTP could not register URL http://+:8000/testservice/. Your process does not have access rights to this namespace 解决方案
    [原]ASP.NET MVC 3 Razor + jqGrid 示例
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6959083.html
Copyright © 2020-2023  润新知