孤独一生

xiaoxiao2025-10-06  18

题目描述

下课了, Polo 来到球场,但他到了之后才发现……被放了飞机……

无事可做的他决心找点乐子,比方说……跳台阶……

球场边有 N 个台阶拍成一行,第 i 个台阶的高度是 Hi(0<Hi<=10^9),第 0个台阶,也就是地面的高度为 0。

Polo 打算把这 N 个台阶分成两个集合 Sa,Sb(可以为空),对于一个台阶集合 S={P1,P2,…P|S|},

其中 P1<P2<…<P|S|,他需要花费 的体力值来完成。

现在他希望两次跳跃所需的总体力值最小,你能帮帮他吗?

题解

考虑一个O(n^2)DP,我们假定 f [ i ] [ j ] f[i][j] f[i][j]表示 A A A集合以 i i i结尾, B B B集合以 j j j结尾, i &gt; j i&gt;j i>j。我们画个图就可以发现 当 i , j 之 间 有 空 格 的 时 候 , f [ i ] [ j ] = f [ i − 1 ] + a b s ( h [ i ] − h [ i − 1 ] ) , i &gt; j + 1 当i,j之间有空格的时候,f[i][j]=f[i-1]+abs(h[i]-h[i-1]),i&gt;j+1 i,jf[i][j]=f[i1]+abs(h[i]h[i1]),i>j+1没有空格的时候我们要枚举 f [ i ] [ i − 1 ] = m i n ( f [ i − 1 ] [ k ] + a b s ( h [ i ] − h [ k ] ) + a b s ( h [ i ] − h [ k ] ) f[i][i-1]=min(f[i-1][k]+abs(h[i]-h[k])+abs(h[i]-h[k]) f[i][i1]=min(f[i1][k]+abs(h[i]h[k])+abs(h[i]h[k])可以理解为枚举B的长度(A,B)并不绝对,只是表示一个互异关系。 那么我们可以发现前者很好转移,后者不好转移,于是我们思考后者,其实我们发现后者的dp可以单独拿出来做记 g [ i ] = f [ i ] [ i − 1 ] g[i]=f[i][i-1] g[i]=f[i][i1],则 g [ i ] = m i n ( g [ j ] + s u m [ i − 1 ] − s u m [ j ] + a b s ( h [ i ] − h [ j − 1 ] ) g[i]=min(g[j]+sum[i-1]-sum[j]+abs(h[i]-h[j-1]) g[i]=min(g[j]+sum[i1]sum[j]+abs(h[i]h[j1])同样可以理解成枚举集合长度。那么我们把绝对值拿掉就好做了,考虑做一个权值树状数组,一切就显然了。

代码

#include<bits/stdc++.h> #define maxn 500005 #define INF 0x3f3f3f3f #define LL long long using namespace std; LL read(){ LL res,f=1; char c; while(!isdigit(c=getchar())) if(c=='-') f=-1; res=(c^48); while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48); return res*f; } int p=1,n,h[maxn],d[maxn],rk[maxn]; LL sum[maxn],f[maxn],ans=INF; struct TR{ LL arr[maxn]; TR(){ memset(arr,0x3f,sizeof arr); } void update(int x,LL w,int f){ for(;x>0 && x<=p;x+=f*(x&-x)){ arr[x]=min(arr[x],w); } } LL query(int x,int f){ LL res=INF; for(;x>0 && x<=p;x-=f*(x&-x)){ res=min(arr[x],res); } return res; } }a,b; //a:h[j]<h[i] b:h[j]>=h[i] bool cmp(int x,int y){return h[x]<h[y];} int main(){ n=read(); for(int i=1;i<=n;i++){ h[i]=read(); d[i]=i; sum[i]=sum[i-1]+abs(h[i]-h[i-1]); } sort(d+1,d+n+1,cmp); for(int i=1;i<=n;i++) rk[d[i]]=h[d[i]]==h[d[i-1]]?p:++p; f[1]=h[1]; a.update(1,0,1); b.update(1,0,-1); ans=sum[n]; for(int i=2;i<=n;i++){ f[i]=sum[i-1]+min(a.query(rk[i],1)+h[i],b.query(rk[i],-1)-h[i]); a.update(rk[i-1],f[i]-sum[i]-h[i-1],1); b.update(rk[i-1],f[i]-sum[i]+h[i-1],-1); ans=min(ans,f[i]+sum[n]-sum[i]); } printf("%lld\n",ans); return 0; }
转载请注明原文地址: https://www.6miu.com/read-5037470.html

最新回复(0)