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;	
    }
    
    
  • 相关阅读:
    700. Search in a Binary Search Tree
    100. Same Tree
    543. Diameter of Binary Tree
    257. Binary Tree Paths
    572. Subtree of Another Tree
    226. Invert Binary Tree
    104. Maximum Depth of Binary Tree
    1、解决sublime打开文档,出现中文乱码问题
    移植seetafaceengine-master、opencv到ARM板
    ubuntu16.04-交叉编译-SeetaFaceEngine-master
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10647424.html
Copyright © 2011-2022 走看看