zoukankan      html  css  js  c++  java
  • Codeforces Round #622(Div 2)C2. Skyscrapers (hard version)

    题目链接 :

    C2. Skyscrapers (hard version)

    题目描述 :

    与上一道题类似,只是数据范围变大, 5e5, 如果用我们原来的方法,铁定是超时的。
    

    考察点 :

    单调栈,贪心,前缀和,后缀和
    

    析题得侃:

    上面说了,用原先得方法得话是铁定超时的,那怎么优化呢?通过 easy version ,我们可以
    得知合适的位置一定是由两部分组成的,左侧的数的和,右侧的数的和,我们求这些和的时候
    也确实浪费了大量的时间,我们能否知道这个位置,然后直接得到这个位置的和呢?然后直接
    取一下最大值。
    我们知道左右两侧一定是单调的,那么既然是单调的,我们能不能用单调栈来维护呢?
    显然是可以的。
    怎么维护呢?
    看一组数据 : 
    下标 : 1 2 3 4 5 6 
    数值 : 5 2 3 6 7 4 (假设现在都在左侧,还没有找到合适的中间位置)
    我们发现 2 的左侧必须 <= 2,同样的, 4 的左侧必须 <= 4,但是 有些数本来就比 4 小
    所以 pre[6] = pre[3] + a[6] * (6 - 3)
    同理,后缀也是一样的,逆过来就可以了
    接下来我们要求某个位置的和就是 : sum = pre[i] + suf[i + 1]
    

    Code:

    #include <stack>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 5e5 + 10;
    
    typedef long long LL;
    
    LL a[maxn],pre[maxn],suf[maxn];
    LL L[maxn],R[maxn];
    
    int n;
    
    stack<int>S;
    
    int main(void) {
    	scanf("%d",&n);
    	for(int i = 1; i <= n; i ++) {
    		scanf("%lld",&a[i]);
    	}
            // 便于我们处理,可以先入栈一个 0
    	S.push(0);
    	for(int i = 1; i <= n; i ++) {
    		while(a[i] <= a[S.top()]) S.pop();
    		L[i] = S.top();
    		S.push(i);
    	}
    	while(!S.empty()) S.pop();
            //同上
    	S.push(n + 1);
    	for(int i = n; i ; i --) {
    		while(a[i] <= a[S.top()]) S.pop();
    		R[i] = S.top();
    		S.push(i);
    	}
            //计算每个位置的前缀和
    	for(int i = 1; i <= n; i ++) {
    		LL l = L[i];
    		pre[i] = pre[l] + a[i] * (i - l);
    	}
            //计算每个位置的后缀和
    	for(int j = n; j ; j --) {
    		LL r = R[j];
    		suf[j] = suf[r] + a[j] * (r - j);
    	}
            // 寻找合适的位置
    	LL sum = pre[1] + suf[2],id = 1;
    	for(int i = 1; i <= n; i ++ ) {
    		if(sum < pre[i] + suf[i + 1]) {
    			id = i;
    			sum = pre[i] + suf[i + 1];
    		}
    	}
    	for(int i = id - 1; i >= 1; i --) {
    		a[i] = min(a[i + 1],a[i]);
    	}
            // 中间的那两个位置一定是 ok 的,我们需要从下一个开始
    	for(int j = id + 2; j <= n; j ++) {
    		a[j] = min(a[j - 1],a[j]);
    	}
    	for(int i = 1; i <= n; i ++) {
    		cout << a[i] << " ";
    	}
    	cout << endl;
    	return 0;
    }
    

    后记 :

    优化往往是再复杂的基础上进行优化,根据某些性质,利用相应的数据结构进行优化。
  • 相关阅读:
    SpringSource发布Spring Data Redis 1.0.0
    C#实现的GDI+时钟
    敏捷团队应对打扰的七种方法
    JBoss发布Hibernate 4.0
    在 IE10 的 XHR 的麦子
    Spring AMQP 1.0 GA发布了
    对 64 个以上逻辑处理器使用任务管理器
    预览Visual Studio11: 敏捷的支持、团队协作以及代码克隆监测
    在 Windows 8 中支持传感器
    HTTP API可演进性最佳实践
  • 原文地址:https://www.cnblogs.com/prjruckyone/p/12357768.html
Copyright © 2011-2022 走看看