孤独一生
题目描述
下课了,Polo来到球场,但他到了之后才发现…..被放了飞机……
无事可做的他决心找点乐子,比方说……跳台阶……
球场边有N个台阶拍成一行,第i个台阶的高度是Hi(0< mHi<=10^9),第0个台阶,也就是地面的高度为0。Polo打算把这N个台阶分成两个集合Sa,Sb(可以为空),对于一个台阶集合S={P1,P2,…P|S|},其中P1< P2< …< P|S|,他需要花费
sigma{|S| i=1} {Hpi-Hpi-1}
的体力值来完成。
现在他希望两次跳跃所需的总体力值最小,你能帮帮他吗?
输入
第一行一个数N。
第二行N个整数Hi。
输出
一行一个整数,表示最小的总体力值。
样例输入
3
1 3 1
样例输出
4
提示
对于10%的数据N<=20。
对于20%的数据N<=100。
对于50%的数据N<=5000。
对于100%的数据1<=N<=500000。
来源
中山纪念2014八校
这道题DP非常好想,可是只有50分
发现求解中有abs(),可以用(线段树+离散化)维护大于h[i]和小于h[i]的数
分开比较
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
ll f[600000];
int h[600000];
ll sum[600000];
int main(){
int n;
scanf("%d",&n);
if (n>5000){
printf("Hello\n");
return 0;
}
for (int i=1;i<=n;++i) scanf("%d",&h[i]);
h[0]=0;
sum[0]=0;
for (int i=1;i<=n;++i)
sum[i]=sum[i-1]+abs(h[i]-h[i-1]);
for (int i=1;i<=n;++i) f[i]=1ll<<60;
f[0]=0;
for (int i=1;i<=n;++i){
for (int j=0;j<i;++j)
f[i]=min(f[i],f[j]+sum[i-1]-sum[j]+abs(h[i]-h[j-1]));
//cout<<i<<" "<<f[i]<<endl;
}
for(int i=1;i<=n;i++)f[n]=min(f[n],f[i]+sum[n]-sum[i]);
printf("%lld\n",f[n]);
//while (1);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
ll f[600000];
int h[600000];
ll sum[600000];
int dis[600000];
struct diz{
ll v,p;
}z[500010];
bool cmp(diz a ,diz b){
return a.v<b.v;
}
struct node{
ll T[5000010];
void build(){
memset(T,120,sizeof(T));
}
void change(int p,int l,int r,int x,ll y){
T[p]=min(T[p],y);
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) change(p+p,l,mid,x,y);
else change(p+p+1,mid+1,r,x,y);
}
ll query(int p,int l,int r,int x,int y){
if (x>r||y<l) return 1ll<<60;
if (x<=l&&y>=r) return T[p];
int mid=(l+r)>>1;
return min(query(p+p,l,mid,x,y),query(p+p+1,mid+1,r,x,y));
}
}q1,q2;
int main(){
int n;
scanf("%d",&n);
for (int i=1;i<=n;++i){
scanf("%d",&h[i]);
z[i].v=h[i];
z[i].p=i;
}
h[0]=0;
sum[0]=0;
for (int i=1;i<=n;++i)
sum[i]=sum[i-1]+abs(h[i]-h[i-1]);
sort(z+1,z+1+n,cmp);
for(int i=1;i<=n;i++) dis[z[i].p]=i;
q1.build();
q2.build();
f[0]=0;
q1.change(1,0,n,0,0);
q2.change(1,0,n,0,0);
for (int i=1;i<=n;++i){
ll x=q1.query(1,0,n,0,dis[i]);
ll y=q2.query(1,0,n,dis[i],n);
//f[i]=min(f[i],f[j]+sum[i-1]-sum[j]+abs(h[i]-h[j-1]));
f[i]=min(x+sum[i-1]+h[i],y+sum[i-1]-h[i]);
q1.change(1,0,n,dis[i-1],f[i]-sum[i]-h[i-1]);
q2.change(1,0,n,dis[i-1],f[i]-sum[i]+h[i-1]);
// cout<<x+sum[i-1]+h[i]<<" "<<y+sum[i-1]-h[i]<<endl;
}
for(int i=1;i<=n;i++)f[n]=min(f[n],f[i]+sum[n]-sum[i]);
printf("%lld\n",f[n]);
//while (1);
return 0;
}