NORMA2 - Norma [cdq分治]

题面

洛谷

你有一个长度为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("----------------\n");
    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\n", 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\n", 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;	
}

posted @ 2019-04-03 10:55  hjmmm  阅读(137)  评论(0编辑  收藏  举报