• P4027 [NOI2007]货币兑换


    题目链接

    题不难,但是经典。

    容易推得DP式子:

    [f_i=MAX(A_ig_j+B_ih_j) ]

    其中

    [g_j=frac{R_jf_j}{A_jR_j+B_j} ]

    [h_j=frac{f_j}{A_jR_j+B_j} ]

    容易想到:

    [f_i/A_i=g_j+frac{B_i}{A_i}h_j ]

    转化为一维斜率优化的基本形式。

    然后我们发现,凸包的横坐标和询问的斜率都不是单调的!

    怎么办?动态凸包?平衡树难写难调常数爆炸?

    这时候,我们可以考虑CDQ分治。与 购票 一题类似,先递归左边,再考虑左对右的贡献,最后递归右边。

    复杂度:(O(nlogn))

    关键代码:

    ...
    void cdq(int l, int r) {
    	if (l == r) {
    		if (l)	MAX(f[l], f[l - 1]);
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	cdq(l, mid);
    	int tot = 0;
    	for (register int i = l; i <= mid; ++i)
    		tu[++tot] = (node){i, f[i] / (R[i] * A[i] + B[i])};//Attention!!
    	sort(tu + 1, tu + 1 + tot);
    	stop = 0;//Attention!!
    	for (register int nw = 1; nw <= tot; ++nw) {
    		int j = tu[nw].cur;
    		vectors xl(f[j] / (R[j] * A[j] + B[j]), -f[j] * R[j] / (R[j] * A[j] + B[j]));
    		while (stop > 1 && (stk[stop] - stk[stop - 1]) * (xl - stk[stop - 1]) <= 0)	--stop;
    		stk[++stop] = xl;
    	}
    	tot = 0;
    	for (register int i = mid + 1; i <= r; ++i)	qu[++tot] = (node){i, B[i] / A[i]};
    	sort(qu + 1, qu + 1 + tot);
    	int st = 1;
    	for (register int nw = 1; nw <= tot; ++nw) {
    		int i = qu[nw].cur;
    		vectors xl(1, B[i] / A[i]);
    		while (stop - st >= 1 && (stk[st + 1] - stk[st]) * xl >= 0) ++st;
    		MAX(f[i], A[i] * (xl.y * stk[st].x - stk[st].y));
    	}
    	cdq(mid + 1, r);
    }
    ...
    int main() {
    	...
        for (register int i = 1; i <= n; ++i) {
    		scanf("%lf%lf%lf", &A[i], &B[i], &R[i]);
    	}
    	f[1] = s;
    	cdq(1, n);//Attention!!
        ...
    }
  • 相关阅读:
    leetcode-剑指19-OK
    leetcode-剑指38-?
    leetcode-剑指36-OK
    leetcode-剑指41-OK
    leetcode-剑指20-OK
    leetcode-剑指16-OK
    nginx重写路由隐藏入口文件报错引发的思考
    Go之并发
    Go之接口
    Go实现学生管理系统
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13429749.html
Copyright © 2020-2023  润新知