• 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
    ",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
    ",ans);
    }
    
    int main(){
    	init(),work();
    	return 0;
    }
    




  • 相关阅读:
    测试工作效率低思考和改进
    Linux环境变量配置方法
    Linux上error while loading shared libraries问题解决方法
    PyCharm工具配置和快捷键使用
    Linux chattr和lsattr命令使用方法
    PuTTY工具配置和使用方法
    Python+AutoIt实现界面工具开发
    我对测试工作的一些认识
    Windows终端工具_MobaXterm
    Cygwin工具安装和使用指导书
  • 原文地址:https://www.cnblogs.com/thythy/p/5493502.html
Copyright © 2020-2023  润新知