zoukankan      html  css  js  c++  java
  • 【洛谷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;
    }
    
  • 相关阅读:
    codeforces C. Fixing Typos 解题报告
    codeforces B. The Fibonacci Segment 解题报告
    codeforces B. Color the Fence 解题报告
    codeforces B. Petya and Staircases 解题报告
    codeforces A. Sereja and Bottles 解题报告
    codeforces B. Levko and Permutation 解题报告
    codeforces B.Fence 解题报告
    tmp
    API 设计 POSIX File API
    分布式跟踪的一个流行标准是OpenTracing API,该标准的一个流行实现是Jaeger项目。
  • 原文地址:https://www.cnblogs.com/stoorz/p/13883819.html
Copyright © 2011-2022 走看看