• Codeforces 601B(贪心+斜率+组合数学+单调栈)


    题面

    传送门
    题目大意:
    L(h)的值是区间[L,R]内,abs(h[i]-h[j])/(i-j)的最大值。现在有q个询问,每个询问表示询问区间[L,R]内,所有子序列的L(h)的值的和

    分析

    |h[i]h[j]ij|想成斜率,显然选相邻的两个数最优,最大的斜率只会存在于相邻两点
    所以我们可以预处理所有h[i]-h[i-1]的值,记作d[i]
    问题转化为求[L,R]中每个子区间中的最大d[i]之和

    朴素算法是枚举所有子区间,时间复杂度O(n2),显然会TLE
    因此我们可以计算每个d[i]被算了多少次
    具体方法如下:
    维护一个单调栈,从左到右依次将d[i]入栈,栈顶元素最小
    那么过程中,当区间左端点<=i-1时,区间最大值为弹出栈顶的元素
    当区间右端点>=i+1时,区间最大值为新加入进去的元素
    所谓x的作用,就是区间端点在a左侧或在b右侧时,区间内的最大值为x,此时便是”有作用”的,因为会被算进结果里
    如d={2,5,3,9,8,1}
    将5入栈时弹出2,则区间右端点小于等于1时,区间最大值为2
    当区间左端点>=2时,区间最大值为5 (当然此时还没有计算出右端点,之后9入栈可以计算出右端点<=3时区间最大值为5)

    设lbound[i],rbound[i]表示区间左端点>=lbound[i]且区间右端点<=rbound[i]时区间最大值为d[i],查询区间为[L,R]
    则由乘法原理得,d[i]被计算了(i-lbound[i]+1)*(rbound[i]-i+1)次
    于是对于每一个i,我们可以O(1)的时间内求出结果

    单调栈预处理时间复杂度O(n),查询时间复杂度为O(nq)
    一些陷阱:

    1.数据范围:最后答案要用long long
    2.单调栈最后里面元素要出栈,它们的rbound值为n
    3.若单调栈为空,新插入的元素的lbound值为1

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<stack> 
    #include<algorithm>
    #include<cmath>
    #define maxn 100005 
    #define ForMyLove return 0;
    using namespace std;
    int n,q;
    int a[maxn];
    int lbound[maxn],rbound[maxn]; 
    long long d[maxn];
    struct node{
        int pos;
        int value;
        node(){
    
        }
        node(int i,int x){
            pos=i;
            value=x;
        }
    }; 
    stack<node>s;
    int main(){
        int l,r;
        scanf("%d %d",&n,&q);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) d[i]=abs(a[i]-a[i-1]);
        for(int i=1;i<=n;i++){
            node now;
            while(!s.empty()){
                now=s.top();
                if(d[i]>now.value){
                    rbound[now.pos]=i-1;
                    s.pop();
                }else break;
            }
            if(s.size()==0) lbound[i]=1;
            else{
                now=s.top();
                lbound[i]=now.pos+1;
            }
            s.push(node(i,d[i]));
        }
        while(!s.empty()){
            node now=s.top();
            rbound[now.pos]=n;
            s.pop();
        }
        while(q--){
            scanf("%d %d",&l,&r);
            long long ans=0;
            for(int i=l+1;i<=r;i++){
                long long left=max(l+1,lbound[i]);
                long long right=min(r,rbound[i]);
                ans=ans+(i-left+1)*(right-i+1)*d[i];
            }
            printf("%I64d
    ",ans);
        }
        ForMyLove
    } 
  • 相关阅读:
    iOS 渐变进度条
    征服Spark as a Service
    在云计算资源池上自动部署业务应用的大数据平台组件开发实战
    一天征服Spark!
    王家林最新最新介绍
    决胜大数据时代:Hadoop&Yarn&Spark企业级最佳实践(8天完整版脱产式培训版本)
    决胜大数据时代:Hadoop&Yarn&Spark企业级最佳实践(3天)
    精通Spark的开发语言:Scala最佳实践
    精通Spark:Spark内核剖析、源码解读、性能优化和商业案例实战
    基于Spark构建开放式的云计算平台第一阶段课程
  • 原文地址:https://www.cnblogs.com/birchtree/p/9858041.html
Copyright © 2020-2023  润新知