zoukankan      html  css  js  c++  java
  • 洛谷 P4655 [CEOI2017]Building Bridges

    (n) 根柱子依次排列,每根柱子都有一个高度。第 (i) 根柱子的高度为 (h_i)

    现在想要建造若干座桥,如果一座桥架在第 (i) 根柱子和第 (j) 根柱子之间,那么需要 ((h_i-h_j)^2)​​ 的代价。

    在造桥前,所有用不到的柱子都会被拆除,因为他们会干扰造桥进程。第 (i) 根柱子被拆除的代价为 (w_i),注意 (w_i) 不一定非负,因为可能政府希望拆除某些柱子。

    现在政府想要知道,通过桥梁把第 (1) 根柱子和第 (n) 根柱子连接的最小代价。注意桥梁不能在端点以外的任何地方相交。

    首先考虑dp,设(f_i)表示第(i)个柱子和第(1)个柱子连接所需要的最小代价,那么可以写出状态转移方程:

    [f_i=Min_{j=1}^{i-1}f_j+sw_{i-1}-sw_j+(h_i-h_j)^2 ]

    其中(sw_i=sum_{j=1}^iw_j),然后对式子稍微变一下形:

    [f_i=sw_{i-1}+h_i^2+Min_{j=1}^{i-1}-2h_jh_i+f_j-sw_j+h_j ]

    后面的部分可以看成一条关于(h_i)的线段,于是我们可以直接用李超树维护。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 1e6 + 10;
    const long long inf = 1e16;
    using namespace std;
    int n,h[N + 5],w[N + 5],cc;
    long long sw[N + 5],f[N + 5];
    double b[N + 5],k[N + 5];
    double val(int id,int x)
    {
    	if (!id)
    		return inf;
    	return k[id] * x + b[id];
    }
    bool cmp(int a,int b,int x)
    {
    	double fa = val(a,x),fb = val(b,x);
    	return fa < fb;
    }
    struct Seg
    {
    	#define zrt k << 1
    	#define yrt k << 1 | 1
    	int mx[N * 5 + 5];
    	void update(int k,int l,int r,int x,int y,int nw)
    	{
    		if (r < x || l > y)
    			return;
    		if (l >= x && r <= y)
    		{
    			if (cmp(mx[k],nw,l) && cmp(mx[k],nw,r))
    				return;
    			if (cmp(nw,mx[k],l) && cmp(nw,mx[k],r))
    			{
    				mx[k] = nw;
    				return;
    			}
    			int mid = l + r >> 1;
    			if (cmp(nw,mx[k],mid))
    				swap(nw,mx[k]);
    			if (cmp(nw,mx[k],l))
    				update(zrt,l,mid,x,y,nw);
    			else
    				update(yrt,mid + 1,r,x,y,nw);
    			return;
    		}
    		int mid = l + r >> 1;
    		update(zrt,l,mid,x,y,nw);
    		update(yrt,mid + 1,r,x,y,nw);
    	}
    	int query(int k,int l,int r,int x)
    	{
    		if (x < l || x > r)
    			return 0;
    		if (l == r && l == x)
    			return mx[k];
    		int mid = l + r >> 1,res;
    		if (x <= mid)
    			res = query(zrt,l,mid,x);
    		else
    			res = query(yrt,mid + 1,r,x);
    		if (cmp(mx[k],res,x))
    			res = mx[k];
    		return res;
    	}
    }tree;
    int main()
    {
    	scanf("%d",&n);
    	for (int i = 1;i <= n;i++)
    		scanf("%d",&h[i]);
    	for (int i = 1;i <= n;i++)
    	{
    		scanf("%d",&w[i]);
    		sw[i] = sw[i - 1] + w[i];
    	}
    	cc++;
    	k[cc] = -2 * h[1];
    	b[cc] = -sw[1] + 1.0 * h[1] * h[1];
    	tree.update(1,0,N,0,N,cc);
    	for (int i = 2;i <= n;i++)
    	{
    		int num = tree.query(1,0,N,h[i]);
    		f[i] = sw[i - 1] + 1ll * h[i] * h[i] + val(num,h[i]);
    		cc++;
    		k[cc] = -2 * h[i];
    		b[cc] = f[i] - sw[i] + 1.0 * h[i] * h[i];
    		tree.update(1,0,N,0,N,cc);
    	}
    	cout<<f[n]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Redis基础
    Windows 10 中 安装 RabbitMQ
    Nginx
    第二章-矩阵
    第一章-行列式
    第六章-微分方程
    第五章-多元函数
    第四章-定积分
    第三章-不定积分
    第二章-导数
  • 原文地址:https://www.cnblogs.com/sdlang/p/13917492.html
Copyright © 2011-2022 走看看