zoukankan      html  css  js  c++  java
  • [题解] LuoguP4655 [CEOI2017]Building Bridges

    https://www.luogu.com.cn/problem/P4655

    总之先考虑一个暴力DP,令(f[i])表示连接(1)(i)的最小代价,有转移

    [f[i]=min_{j=1}^{i-1} {f[j]+(h[i]-h[j])^2+s[i-1]-s[j]} ]

    其中(s[k]=sum_{i=1}^k w[i])

    发现有个平方项,好像是斜率优化的亚子,我们来写一写

    [f[i]=f[j]+h[i]^2+h[j]^2-2h[i]h[j]+s[i-1]-s[j] ]

    做整理得到

    [2h[i]h[j]+f[i]-h[i]^2-s[i-1]=f[j]-s[j]+h[j]^2 ]

    (x=h[j],y=f[j]-s[j]+h[j]^2,b=f[i]-h[i]^2-s[i-1],k=2h[i]),那么这是一条(y=kx+b)的直线。

    我们要最小化截距(b),于是维护下凸壳就好了。

    哇窝切黑题了QAQ

    too young too simple

    注意到这里的(x)(k)都不是单调的......如果只是(k)不单调可以在凸壳上二分,但(x)不单调维护凸包都是个问题......

    我会平衡树!

    不你不会...

    窝会李超树!

    那是啥...

    考虑(CDQ)分治...即对于当前区间([l,r])先完成([l,mid])内的转移,再建出([l,mid])里的点所组成的下凸壳,然后把([mid+1,r])里的位置按(2h[i])排序,单调队列维护决策点完成([l,mid] ightarrow [mid+1,r])的转移即可。

    提前就按(h)排好序可以少一个(log) QAQ。

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;++i)
    #define per(i,a,n) for (int i=n-1;i>=a;--i)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define all(x) (x).begin(),(x).end()
    #define SZ(x) ((int)(x).size())
    typedef double db;
    typedef long long ll;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    
    const int N=2e5+10;
    const ll INF=1e18;
    int n;
    ll s[N],h[N],f[N];
    
    inline ll sqr(ll x) {return x*x;}
    inline ll X(int i) {return h[i];}
    inline ll Y(int i) {return f[i]-s[i]+sqr(h[i]);}
    inline db slope(int i,int j) {
    	if (X(i)==X(j)) return Y(i)>Y(j)?INF:-INF;
    	else return 1.0*(Y(i)-Y(j))/(X(i)-X(j));
    }
    
    int p[N],q[N];
    void cdq(int l,int r) {
    	if (l==r) {return;}
    	int mid=(l+r)>>1,t1=l-1,t2=mid;
    	static int tmp[N];
    	rep(i,l,r+1) {
    		if (p[i]<=mid) tmp[++t1]=p[i];
    		else tmp[++t2]=p[i];
    	}
    	rep(i,l,r+1) p[i]=tmp[i];
    	cdq(l,mid);
    	t1=1,t2=0;
    	rep(i,l,mid+1) {
    		while (t1<t2&&slope(p[i],q[t2-1])<=slope(q[t2],q[t2-1])) --t2;
    		q[++t2]=p[i];
    	}
    	rep(i,mid+1,r+1) {
    		while (t1<t2&&2.0*h[p[i]]>=slope(q[t1+1],q[t1])) ++t1;
    		int k1=p[i],k2=q[t1];
    		// cout<<k1<<" <- "<<k2<<endl;
    		f[k1]=min(f[k1],f[k2]+s[k1-1]-s[k2]+sqr(h[k1]-h[k2]));
    	}
    	cdq(mid+1,r);
    	t1=l,t2=mid+1;
    	rep(i,l,r+1) {
    		if (t2>r||(t1<=mid&&h[p[t1]]<h[p[t2]])) tmp[i]=p[t1++];
    		else tmp[i]=p[t2++];
    	}
    	rep(i,l,r+1) p[i]=tmp[i];
    }
    
    int main() {
    #ifdef LOCAL
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	rep(i,1,n+1) scanf("%lld",&h[i]),p[i]=i,f[i]=INF;
    	f[1]=0;
    	rep(i,1,n+1) {
    		ll w; scanf("%lld",&w);
    		s[i]=s[i-1]+w;
    	}
    	sort(p+1,p+n+1,[](int i,int j){return h[i]<h[j];});
    	cdq(1,n);
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    明确方向,勇往直前
    每日一笔记之3:QTconnect()
    每日一笔记之2:QT之坐标系统:
    每日一笔记之1:静态成员函数
    QT对话框模式与非模式
    Objective-C-实例变量与属性的关系
    Objective-C编码规范
    CocoaPods的安装与使用
    design_model(18)observe
    design_model(17)state
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12587262.html
Copyright © 2011-2022 走看看