zoukankan      html  css  js  c++  java
  • 单调栈poj2796

    题意:给你一段区间,需要你求出(在这段区间之类的最小值*这段区间所有元素之和)的最大值......

    例如:

    6
    3 1 6 4 5 2

    以4为最小值,向左右延伸,6 4 5  值为60.......

    思路:解决完为这道题目,我才真正明白了单调栈的原理,它就是以某一个值为最小(最大)值,向这个值的两侧延伸,遇到大于它(小于它)的值,就将它延伸的范围扩大,当然,一般来说,要这样做的算法复杂度为o(n^2),但是借助栈这个玩意,维护其单调增(减),就可以在o(n)的时间复杂度解决这个问题。将一元素加入栈时,先判断它是否大于(小于)栈顶元素,若是大于(小于)栈顶元素,加入栈。(从这里开始只讲维护单调增栈)否则,将栈顶元素出栈,直到栈顶元素小于要加入栈的元素,在此过程中,需要维护向前延伸和向后延伸的问题,当要加入栈的元素之前有n个栈元素出栈,那么说明这n个出栈的元素都会大于或者等于要入栈的元素,此时,我们需要维护入栈元素可以向前延伸多少个元素(相当于记录它的前面有多少个元素比它大),而每个栈顶元素要向出栈了的元素延伸,因为在出栈了的元素一定是比它的大的元素(根据我维护的是单调增栈)......这样,就在o(n)的时间复杂度内解决了上述问题.........

    例如:3 1 6 4 5 2

    (3,1,1)  (1,2,2)  (6,3,3)  (4,4,4)  (5,5,5)  (2,6,6)

    首先每个元素自己本身的前后延伸都为1,把3加入栈,1<3,把3出栈,用1的前延伸加上3的前延伸,如此变为(1,1,2),6<1,入栈,变成(1,1,2)(6,3,3),

    4<6,将6出栈,4向前延伸,1向后延伸变成(1,1,3) (4,3,4) 

    5>4,入栈,变成(1,1,3)(4,3,4)(5,5,5)

    2<5,5出栈,2向前延伸,4向后延伸,变成(1,1,3)(4,3,5)                   2还未入栈(2,5,6)

    2<4,4出栈,2向前延伸,1向后延伸,变成(1,1,5) (2,3,6).....

    一次类推,会发现最大的结果在(4,3,5)这里这意味着,以4为最小值的区间范围为3————5,也就是6 4 5  

    #include<iostream>
    #include<stack>
    #include<stdio.h>
    using namespace std;
    #define maxx 110000
    __int64 str[maxx],t[maxx];
    struct node
    {
    	__int64 num,pre,next;    //num记录数值,pre记录向前延伸多少个,next记录向后延伸多少个,k记录本身所处的位置 
    	__int64 k;
    };
    int main()
    {
    	int n;
    	while(scanf("%d",&n)>0)
    	{
    		stack<node>Q;
    		node tmp;
    		__int64 ans=-100,sum=-100,num;
    		str[0]=0;
    		for(__int64 i=1;i<=n;i++)
    		{
    			scanf("%I64d",&t[i]);
    			if(i==1)
    			str[i]=t[i];
    			else
    			str[i]=str[i-1]+t[i];
    		}
    	    tmp.num=t[1];
    		tmp.pre=1;
    		tmp.next=1;
    		tmp.k=1;
    		Q.push(tmp);
    		__int64 x=0,y=0;
    		for(__int64 i=2;i<=n;i++)
    		{
    			node tmp1;
    			tmp1.num=t[i];
    			tmp1.pre=tmp1.next=1;
    			tmp1.k=i;
    			while(!Q.empty()&&tmp1.num<=Q.top().num)
    			{
    				tmp=Q.top();
    				Q.pop();
    				if(!Q.empty())
    				Q.top().next+=tmp.next;
    				tmp1.pre+=tmp.pre;
    				ans=tmp.num*(str[tmp.k+tmp.next-1]-str[tmp.k-tmp.pre]);
    				if(ans>=sum)
    				{
    					sum=ans;
    					x=tmp.k-tmp.pre+1;
    					y=tmp.k+tmp.next-1;
    				}
    			}
    			Q.push(tmp1);
    		}
    		while(!Q.empty())
    		{
    			tmp=Q.top();
    			Q.pop();
    			if(!Q.empty())
    			Q.top().next+=tmp.next;
    			ans=tmp.num*(str[tmp.k+tmp.next-1]-str[tmp.k-tmp.pre]);
    			if(ans>=sum)
    			{
    				sum=ans;
    				x=tmp.k-tmp.pre+1;
    				y=tmp.k+tmp.next-1;
    		    }
    		}
    	
    		if(n==0)x=y=0;
    		printf("%I64d
    %I64d %I64d
    ",sum,x,y);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    MyBatis与spring面试题-转载
    122. 买卖股票的最佳时机 II(贪心策略)
    121. 买卖股票的最佳时机
    120. 三角形最小路径和
    236. 二叉树的最近公共祖先(快手面试)
    b,b+树区别
    119. 杨辉三角 II
    118. 杨辉三角
    检查型异常(Checked Exception)与非检查型异常(Unchecked Exception)
    Redis
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/3151556.html
Copyright © 2011-2022 走看看