3999:孤独一生

传送门:然而并没有

题目大意:


思路:首先是O(n^2)的DP

设f[i][j]表示第1个集合结尾为i,第2个集合结尾为j,其中i>=j

分两种情况

f[i][j]=f[i-1][j]+|h[i]-h[i-1]| (i>j+1)(第2个集合结尾是j,那么j+1到i这一段都是第一个集合的)

=min(f[j][k]+|h[i]-h[k]|) (i=j+1) (其中第一个集合结尾已经是j了,而另一个集合结尾现在是i,原先则可以是任意的k<j,因为两个集合没有区别,i>=j,所以交换一下位置)


这时我们发现,只有当i=j+1是转移是不确定的

于是,我们考虑用f[i][i-1]来表示所有状态

记g[i]=f[i][i-1],sum[i]=Σ|h[j]-h[j-1]|(j<=i)就是高度差的前缀和

那么g[i]=min(g[j]+sum[i-1]-sum[j]+|h[i]-h[j-1]|)

答案就是min(g[i]+sum[n]-sum[i])


现在这个方程空间复杂度为O(n)但是时间复杂度还是O(n^2)

考虑如何优化

首先取绝对值,分离已知和未知

g[i]=h[i]+sum[i-1]+min(g[j]-sum[j]-h[j-1])  (h[i]>=h[j-1])

=sum[i-1]-h[i]+min(g[j]-sum[j]+h[j-1])  (h[i]<h[j-1])

开两个树状数组,以离散化后的h为下标,分别记录g[j]-sum[j]-h[j-1]和g[j]-sum[j]+h[j-1],每次在两个树状数组中查询最小值即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls (p<<1)
#define rs ((p<<1)|1)
#define mid ((l+r)>>1)
#define aabs(a) (a>0?a:-(a))
const int maxn=500010,maxt=maxn<<2;
typedef long long ll;
using namespace std;
ll sum[maxn],h[maxn],g[maxn],ans=1ll<<55;int a[maxn],b[maxn],tmp[maxn],n,cnt;//a  离散化后的h 

struct bit{
	ll mins[maxn];
	void clear(){memset(mins,63,sizeof(mins));}
	void modify(int x,ll v){for (;x<=cnt;x+=x&(-x)) mins[x]=min(mins[x],v);}
	ll query(int x){ll res=1ll<<55;for (;x;x-=x&(-x)) res=min(res,mins[x]);return res;}
}t1,t2;

void init(){
	scanf("%d",&n),n++,h[1]=a[1]=tmp[1]=0,t1.clear(),t2.clear(),memset(g,63,sizeof(g));
	for (int i=2;i<=n;i++) scanf("%I64d",&h[i]),a[i]=tmp[i]=h[i],sum[i]=sum[i-1]+aabs(h[i]-h[i-1]);
	sort(tmp+1,tmp+1+n),cnt=unique(tmp+1,tmp+1+n)-tmp-1;
	for (int i=1;i<=n;i++) a[i]=lower_bound(tmp+1,tmp+1+cnt,a[i])-tmp,b[i]=cnt-a[i]+1;
//	for (int i=1;i<=n;i++) printf("fuck%d\n",a[i]);
}

void work(){
	t1.modify(a[1],0),t2.modify(b[1],0);
	for (int i=2;i<=n;i++){
		g[i]=min(g[i],h[i]+sum[i-1]+t1.query(a[i]-1));
		g[i]=min(g[i],sum[i-1]-h[i]+t2.query(b[i]));
		t1.modify(a[i-1],g[i]-sum[i]-h[i-1]);
		t2.modify(b[i-1],g[i]-sum[i]+h[i-1]);
	}
	for (int i=1;i<=n;i++) ans=min(ans,g[i]+sum[n]-sum[i]);
	printf("%I64d\n",ans);
}

int main(){
	init(),work();
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值