zoukankan      html  css  js  c++  java
  • NORMA2

    题面

    洛谷

    你有一个长度为n的序列,定义这个序列中每个区间的价值是
    (Cost(i,j)=Min(Ai...Aj)∗Max(Ai...Aj)∗(j−i+1)Cost(i,j)=Min(A_{i}...A_{j})*Max(A_{i}...A_{j})*(j-i+1))
    其中,(i,j)是区间的两个端点。
    现在请你求出给定序列所有区间的价值之和。
    (n leq 5e5)

    统计所有子区间 考虑cdq分治
    左区间对右区间的贡献如何计算?
    用一个cur从mid到L扫左区间
    mn,mx表示[cur, mid]的最小值和最大值
    对于每一个cur 维护在右区间的两个位置p, q
    p表示[mid + 1, p - 1]的数都大于等于mn 而a[p] < mn
    q表示[mid + 1, q - 1]的数都小于等于mx 而a[q] > mx
    很明显p,q都满足单调性 那么复杂度就可以控制在线性了

    当p<q时
    对于右区间被分成的三个区间[mid + 1, p - 1], [p, q - 1], [q, R]
    mn,mx对这几个区间的贡献推一下式子就好啦
    式子参考
    对了 注意L==R时计算单点贡献

    #include <algorithm>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N = 5e5 + 5;
    const int inf = 0x3f3f3f3f;
    const long long P = 1e9;
    int n; 
    long long a[N], ans, s1[N], s2[N], s3[N], s4[N], s5[N], s6[N];
    /*
    s1 max * min * i
    s2 max * min 
    s3 min * i  
    s4 min 
    s5 max * i
    s6 max
    */
    
    inline long long Sum(long long L, long long R){
        return (L + R) * (R - L + 1) / 2ll % P;
    }
    inline void add(long long x){
       ans = (ans + x %P) % P;	
    }
    
    void cdq(int L, int R){
        if(L == R) {add(a[L] * a[L] % P); return ;}
        int mid = L + ((R - L) >> 1);
        cdq(L, mid); cdq(mid + 1, R);
        
        long long mx = 0, mn = inf;
        s1[mid] = s2[mid] = s3[mid] = s4[mid] = s5[mid]  = s6[mid] = 0;
        //printf("----------------
    ");
        for(int i = mid + 1; i <= R; ++i){
            mx = max(a[i], mx), mn = min(a[i], mn);
            s1[i] = (mn * mx %P * i %P + s1[i -1]) %P;
            s2[i] = (mn * mx %P + s2[i -1])%P;
            s3[i] = (mn * i %P + s3[i -1])%P;
            s4[i] = (mn + s4[i -1]) %P;
            s5[i] = (mx * i %P + s5[i -1])%P;
            s6[i] = (mx + s6[i -1]) %P;
            //printf("%lld %lld %lld %lld %lld %lld %lld %lld
    ", mn, mx, s1[i], s2[i], s3[i], s4[i], s5[i], s6[i]);
        }
        
        mn = inf, mx = 0;
        for(int p = mid + 1, q = mid + 1, i = mid; i >= L; --i){
            mx = max(a[i], mx), mn = min(a[i], mn);
            while(p <= R && a[p] >= mn) ++p;
            while(q <= R && a[q] <= mx) ++q;//边界
            if(p < q){
                add(mx * mn %P * Sum(mid - i + 2, p - i) %P);
                add(mx * (s3[q - 1] - s3[p - 1]) %P + P - mx * (i - 1) %P * (s4[q - 1] - s4[p - 1]) %P);
                add((s1[R] - s1[q - 1]) + P - 1ll * (i - 1) * (s2[R] - s2[q - 1]) % P);	
            }
            else{
                add(mx * mn %P * Sum(mid - i + 2, q - i) %P);
                add(mn * (s5[p - 1] - s5[q - 1]) %P + P - mn * (i - 1) %P * (s6[p - 1] - s6[q - 1]) %P);
                add((s1[R] - s1[p - 1]) + P - 1ll * (i - 1) * (s2[R] - s2[p - 1]) % P);	
            }
        }
        //printf("%lld %d %d
    ", ans, L, R);
    }
    
    int main(){
        scanf("%d", &n);
        a[0] = 0, a[n + 1] = inf;
        for(int i = 1; i <= n; ++i){
            scanf("%lld", &a[i]);	
        }
        cdq(1, n);
        printf("%lld", (ans %P + P) % P);
        return 0;	
    }
    
    
  • 相关阅读:
    C++ 用libcurl库进行http通讯网络编程(转)
    树莓派声音设置
    在Linux终端命令行下播放音乐的命令(Ubuntu)
    2.1 LibCurl编程流程(转)
    linux编译curl库的动态库so(转)
    单片机中断的IE和IP寄存器(摘抄)
    MCS-51系列特殊功能寄存器(摘抄)
    linux c libcurl的简单使用(转)
    普林斯顿结构 VS 哈佛结构
    树莓派(raspberry pi)学习4: 更改键盘布局(转)
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10647424.html
Copyright © 2011-2022 走看看