zoukankan      html  css  js  c++  java
  • 紫书 习题8-18 UVa 11536 (扫描法)

    这道题貌似可以用滑动窗口或者单调栈做, 但是我都没有用到。

    这道题要求连续子序列中和乘上最小值最大, 那么我们就可以求出每一个元素,

    以它为最小值的的最大区间的值, 然后取max就ok了。那么怎么求呢?

    我可以初始化出一个第一个小于当前元素的的元素的位置, 也就是说初始化出以当前元素为最小值的

    左右端点, 求出之后枚举一遍就ok了。

    那么关键是怎么求呢? 这里有一点扫描法的味道。

    假设当前序列为1243 以求右端点为例, 右端点的位置也就是在右侧第一个小于当前元素的元素的位置。

    那么如果序列是递增的, 如开始的123, 那么123任何一个元素的右端点还没有找到, 所以继续往右。

    但是如果遍历到了最右边的3, 显然左边的4 的右端点的值就是这个3, 而1 2则不是。

    那么也就是说, 找到第一个不是大于前一个元素的元素之后(非递增), 那么就可以从右往左更新值, 只要左边的元素

    大于这个元素, 那么就可以更新。而且只要一个更新不了, 那么左边的肯定也更新不了, 因为左边更小。

    但是我们会发现, 下一次更新值的时候, 之前更新到的值还会被再扫一遍, 很浪费时间。

    所以我这里用到了一个链表的结构, 更新完就在链表中去掉这个元素, 那么之后往左遍历的时候就会快很多了。

    所以一个元素只会被更新到一次, 复杂度是O(n)的。

    然后注意如果右边没有比自己小的元素的话, 那么就值就设置为最大右端点+1。

    这样到后来算总和的时候,区间的右端点是这个数组的值-1(因为不包括右侧第一个小于当前元素的元素的位置)
    那么这个时候就刚好是右半边整个区间了。

    左端点类似

    另外要到poj 2796去提交, UVa数据有问题。(我因此WA了好久)


    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<set> 
    #include<functional>
    #include<algorithm>
    #define REP(i, a, b) for(int i = (a); i < (b); i++)
    using namespace std;
    
    const int MAXN = 112345;
    typedef long long ll;
    int r[MAXN], l[MAXN], a[MAXN], n; 
    int pre[MAXN], aft[MAXN], ans_l, ans_r;
    ll sum[MAXN], ans;
    
    int main()
    {
    	while(~scanf("%d", &n))
    	{
    		sum[0] = 0;
    		REP(i, 0, n) 
    		{
    			scanf("%d", &a[i]);
    			sum[i] = (i == 0 ? 0 : sum[i-1]) + a[i];
    			pre[i] = i - 1; aft[i] = i + 1;
    			l[i] = r[i] = 0;
    		}
    		
    		REP(i, 1, n) //求右边第一个小于当前元素的元素的位置 
    			if(a[i] < a[i-1]) 
    			{
    				int pos = i - 1;
    				while(pos >= 0 && a[pos] > a[i])
    				{
    					r[pos] = i;
    					pos = pre[pos];
    					pre[i] = pos;
    				}
    			}
    		REP(i, 0, n) if(r[i] == 0) r[i] = n;
    		
    		for(int i = n - 2; i >= 0; i--) //求左边第一个小于当前元素的元素的位置 
    			if(a[i] < a[i+1]) 
    			{
    				int pos = i + 1;
    				while(pos < n && a[pos] > a[i])
    				{
    					l[pos] = i;
    					pos = aft[pos];
    					aft[i] = pos;
    				}
    			}
    		REP(i, 0, n) if(l[i] == 0) l[i] = -1;
    		
    		ans = -1;
    		REP(i, 0, n)
    		{
    			ll L = l[i] == -1 ? 0 : sum[l[i]];
    			ll R = sum[r[i]-1];
    			ll t = a[i] * (R - L);
    			if(ans < t)
    			{
    				ans = t;
    				ans_l = l[i]+2;
    				ans_r = r[i];
    			}
    		}
    
    		printf("%lld
    %d %d
    ", ans, ans_l, ans_r);
    	}
    	
    	return 0;	
    } 

  • 相关阅读:
    新人入住博客,互相交流,互相进步
    DHCP技术
    一些额外技术
    OSPF技术
    一些常用的命令
    RSTP技术及原理
    BFD原理
    VRRP技术
    Super VLAN技术
    哈希表(HashMap)
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819560.html
Copyright © 2011-2022 走看看