• #李超线段树 or 斜率优化+CDQ分治#洛谷 4655 [CEOI2017]Building Bridges


    题目


    分析

    列出方程即为(dp[i]=min{dp[j]+(h[i]-h[j])^2+s[i-1]-s[j]})

    (dp[j]+h[j]^2-s[j]=2*h[i]*h[j]+dp[i]-s[i-1]-h[i]^2)

    那这就是一个斜率为(2*h[i]),截距为(dp[i]-s[i-1]-h[i]^2)的直线

    那要使截距尽量小,考虑用李超线段树解决

    否则由于(h[i])不具有单调性,考虑CDQ分治,第一维是时间,第二维是(h),斜率优化做


    代码(李超线段树)

    #include <cstdio>
    #include <cctype>
    #define rr register
    using namespace std;
    typedef long long lll;
    const int N=100011,M=1000011;
    struct rec{lll a,b;}line[N];
    lll h[N],s[N],dp[N]; int p[N*40],n;
    inline signed iut(){
    	rr int ans=0,f=1; rr char c=getchar();
    	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans*f;
    }
    inline void print(lll ans){
    	if (ans<0) putchar('-'),ans=-ans;
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline lll calc(int t,int x){return line[t].a*x+line[t].b;}
    inline signed either(int t1,int t2,int x){return calc(t1,x)<calc(t2,x)?t1:t2;}
    inline void update(int k,int l,int r,int x,int y,int z){
    	rr int mid=(l+r)>>1;
    	if (x<=l&&r<=y){
    		if (!p[k]) {p[k]=z; return;}
    		rr lll la=calc(p[k],l),lb=calc(z,l);
    		rr lll ra=calc(p[k],r),rb=calc(z,r);
    		if (la<=lb&&ra<=rb) return;
    		if (la>=lb&&ra>=rb){p[k]=z; return;}
    		rr double pos=(line[p[k]].b-line[z].b)*1.0/(line[z].a-line[p[k]].a);
    		if (la>=lb){
    			if (pos<=mid) update(k<<1,l,mid,x,y,z);
    			    else update(k<<1|1,mid+1,r,x,y,p[k]),p[k]=z;
    		}else{
    			if (pos>mid) update(k<<1|1,mid+1,r,x,y,z);
    			    else update(k<<1,l,mid,x,y,p[k]),p[k]=z;
    		}
    		return;
    	}
    	if (x<=mid) update(k<<1,l,mid,x,y,z);
    	if (mid<y) update(k<<1|1,mid+1,r,x,y,z);
    }
    inline signed query(int k,int l,int r,int x){
    	if (l==r) return p[k];
    	rr int mid=(l+r)>>1;
    	if (x<=mid) return either(p[k],query(k<<1,l,mid,x),x);
    	    else return either(p[k],query(k<<1|1,mid+1,r,x),x);
    }
    signed main(){
    	n=iut(),line[0]=(rec){0,1000000000000000000ll};
    	for (rr int i=1;i<=n;++i) h[i]=iut();
    	for (rr int i=1;i<=n;++i) s[i]=s[i-1]+iut();
    	dp[1]=0,line[1]=(rec){-h[1]<<1,h[1]*h[1]-s[1]},update(1,0,M,0,M,1);
    	for (rr int i=2;i<=n;++i){
    		dp[i]=h[i]*h[i]+s[i-1]+calc(query(1,0,M,h[i]),h[i]);
    		line[i]=(rec){-h[i]<<1,dp[i]+h[i]*h[i]-s[i]},update(1,0,M,0,M,i);
    	}
    	return !printf("%lld",dp[n]);
    } 
    

    代码(斜率优化)

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm> 
    #define rr register
    using namespace std;
    typedef long long lll;
    const int N=100011; const lll inf=1ll<<60;
    int X[N],h[N],a[N],n,b[N],q[N]; lll s[N],dp[N],Y[N];
    inline signed iut(){
    	rr int ans=0,f=1; rr char c=getchar();
    	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans*f;
    }
    inline lll O(int x){return 1ll*x*x;}
    inline lll min(lll a,lll b){return a<b?a:b;}
    bool cmp(int x,int y){return h[x]<h[y];}
    inline double slope(int i,int j){return (X[i]==X[j])?(Y[j]>=Y[i]?inf:-inf):((double)(Y[j]-Y[i])/(X[j]-X[i]));}
    inline void cdq(int l,int r){
    	if (l==r){
    		Y[a[l]]=dp[a[l]]+O(h[a[l]])-s[a[l]];
    		return;
    	}
    	rr int mid=(l+r)>>1,i1=l,j1=mid+1;
    	for (rr int i=l;i<=r;++i)
    	if (a[i]<=mid) b[i1++]=a[i];
    	    else b[j1++]=a[i];
    	for (rr int i=l;i<=r;++i) a[i]=b[i];
    	cdq(l,mid);
    	rr int head=1,tail=0,t=l-1;
    	for (rr int i=l;i<=mid;++i){
    		while (head<tail&&slope(q[tail-1],q[tail])>=slope(q[tail],a[i])) --tail;
    		q[++tail]=a[i];
    	}
    	for (rr int i=mid+1,I=a[i];i<=r;I=a[++i]){
    		while (head<tail&&slope(q[head],q[head+1])<=2*h[I]) ++head;
    		if (head<=tail) dp[I]=min(dp[I],dp[q[head]]+O(h[I]-h[q[head]])+s[I-1]-s[q[head]]);
    	}
    	cdq(mid+1,r);
    	for (i1=l,j1=mid+1;i1<=mid&&j1<=r;)
    	if (X[a[i1]]<X[a[j1]]) b[++t]=a[i1++];
    	    else b[++t]=a[j1++];
    	while (i1<=mid) b[++t]=a[i1++];
    	while (j1<=r) b[++t]=a[j1++];
    	for (rr int i=l;i<=r;++i) a[i]=b[i];
    }
    signed main(){
    	n=iut(),memset(dp,0x3f,sizeof(dp));
    	for (rr int i=1;i<=n;++i) h[i]=iut();
    	for (rr int i=1;i<=n;++i) s[i]=s[i-1]+iut();
    	for (rr int i=1;i<=n;++i) X[i]=h[i],a[i]=i;
    	sort(a+1,a+1+n,cmp),dp[1]=0,cdq(1,n);
    	return !printf("%lld",dp[n]);
    } 
    
  • 相关阅读:
    【BZOJ 2916】 2916: [Poi1997]Monochromatic Triangles (容斥)
    【BZOJ 2024】 2024: [SHOI2009] 舞会 (容斥原理+高精度)
    【BZOJ 3235】 3235: [Ahoi2013]好方的蛇 (单调栈+容斥原理)
    【BZOJ 4710】 4710: [Jsoi2011]分特产 (容斥原理)
    【BZOJ 1853】 1853: [Scoi2010]幸运数字 (容斥原理)
    【BZOJ 3812】 3812: 主旋律 (容斥原理**)
    【BZOJ 2839】 2839: 集合计数 (容斥原理)
    POJ2635——The Embarrassed Cryptographer(高精度取模+筛选取素数)
    POJ2533——Longest Ordered Subsequence(简单的DP)
    POJ2531——Network Saboteur(随机化算法水一发)
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14487662.html
Copyright © 2020-2023  润新知