• 【BZOJ1345】[Baltic2007] 序列问题(单调栈大水题)


    点此看题面

    大致题意: 你可以花费(max{a_i,a_{i+1}})的代价合并相邻两个元素为(max{a_i,a_{i+1}}),求把序列合成一个点的最小代价。

    贪心

    贪心地去思考,我们每次肯定选择序列中最小的数,把它和它两侧中较小的那个数合并。

    这样肯定是最优的,但却并不好维护在区间中删去某一个数。

    然后我们发现,实际上只需要一个数比它两侧的数都小,我们就可以按上面的方式去合并,那么问题就简单了。

    单调栈

    我们维护一个单调递减的单调栈。

    每当栈顶元素小于当前元素,我们就将栈顶元素与栈顶之下的元素和当前元素中较小的那一个合并,然后就可以将其弹出了。

    所以说这道题真是道大水题。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define LL long long
    using namespace std;
    int n,S[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define D isdigit(c=tc())
    		char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    }F;
    int main()
    {
    	RI i,x,T=0;LL t=0;for(F.read(n),i=1;i<=n;++i)
    		{F.read(x);W(T&&S[T]<=x) t+=T^1?min(S[T-1],x):x,--T;S[++T]=x;}//单调栈
    	--T;W(T) t+=S[T--];return printf("%lld",t),0;//清空栈内元素计算贡献
    }
    
  • 相关阅读:
    数据库部署
    css常见问题
    extjs记录
    C#相关问题
    window疑难问题解决
    常用linq
    不同数据库之间的相互链接
    聊天数据库
    无线路由接入
    [转]如何才能让你的简历被谷歌相中
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1345.html
Copyright © 2020-2023  润新知