• 【洛谷P4655】Building Bridges


    题目

    题目链接:https://www.luogu.com.cn/problem/P4655
    (n) 根柱子依次排列,每根柱子都有一个高度。第 (i) 根柱子的高度为 (h_i)

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

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

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

    思路

    (f[i]) 表示一定不拆第 (i) 个柱子,前 (i) 个柱子连接的最小代价。
    那么显然有方程

    [f[i]=min^{i-1}_{j=1}(f[j]+(h_i-h_j)^2+sum^{i-1}_{k=j+1}w_k) ]

    后面的 (sum w) 可以用前缀和优化一下,记 (s_i=sum^{i}_{j=1} w_i),那么

    [f[j]+h_j^2-s_j=2h_ih_j-s_{i-1}+f[i]-h_i^2 ]

    我们要让截距最小化,将第 (j) 个柱子看做二维平面上一个点 ((h_j,f[j]+h_j^2-s_j)),维护下凸壳,然后用一条斜率为 (2h_i) 的直线去扫。
    发现点的横坐标不递增,所以用 cdq 分治离线做一下就好。
    注意当两个点的横坐标一致时,要按照纵坐标从小到大排序。
    时间复杂度 (O(nlog^2 n)),可以做到 (O(nlog n)) 的。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=100010;
    int n,top,st[N];
    ll f[N],s[N];
    
    ll read()
    {
    	ll d=0,g=1; char ch=getchar();
    	while (!isdigit(ch)) { if (ch=='-') g=-1; ch=getchar(); }
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d*g;
    }
    
    struct node
    {
    	ll h,x,y;
    	int id;
    }a[N];
    
    bool cmp1(node x,node y)
    {
    	return x.id<y.id;
    }
    
    bool cmp2(node x,node y)
    {
    	return x.x!=y.x ? x.x<y.x : x.y<y.y;
    }
    
    bool cmp3(node x,node y)
    {
    	return x.h>y.h;
    }
    
    double slope(int x,int y)
    {
    	if (a[x].x==a[y].x) return 10000000000000000.0;
    	return 1.0*(a[y].y-a[x].y)/(a[y].x-a[x].x);
    }
    
    void cdq(int l,int r)
    {
    	if (l==r)
    	{
    		a[l].x=a[l].h;
    		a[l].y=f[l]+a[l].h*a[l].h-s[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	sort(a+l,a+r+1,cmp1);
    	cdq(l,mid);
    	sort(a+l,a+mid+1,cmp2);
    	sort(a+mid+1,a+r+1,cmp3);
    	top=0;
    	for (int i=l;i<=mid;i++)
    	{
    		while (top>1 && slope(st[top],st[top-1])>slope(st[top-1],i)) top--;
    		st[++top]=i;
    	}
    	for (int i=mid+1;i<=r;i++)
    	{
    		while (top>1 && slope(st[top],st[top-1])>2.0*a[i].h) top--;
    		int j=st[top];
    		f[a[i].id]=min(f[a[i].id],f[a[j].id]+(a[i].h-a[j].h)*(a[i].h-a[j].h)+s[a[i].id-1]-s[a[j].id]);
    	}
    	cdq(mid+1,r);
    }
    
    int main()
    {
    	n=read();
    	for (int i=1;i<=n;i++) a[i].h=read(),a[i].id=i;
    	for (int i=1;i<=n;i++) s[i]=s[i-1]+read();
    	memset(f,0x3f3f3f3f,sizeof(f));
    	f[1]=0;
    	cdq(1,n);
    	printf("%lld",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    SAP模块
    生產製造管理模块
    .NET Framework 3.5 SP1安装时下载文件问题及精简方法2(转)
    .NET Framework 3.5 SP1安装时下载文件问题及精简方法(转)
    .net remoting构架(part 2)转
    vbs下一些取特殊路径的方法总结(转)
    SQL安装命令行详解(转)
    InstallShield Basic MSI工程常见问题解答(转)
    在64位平台使用SQL Server Compact(转)
    vbs 创建多级目录方法
  • 原文地址:https://www.cnblogs.com/stoorz/p/13883819.html
Copyright © 2020-2023  润新知