• BZOJ3745: [Coci2015]Norma


    首先分治。

    那么对于区间$[l,r]$中的答案。

    我们只考虑经过$mid$和$mid+1$的答案。

    然后枚举左端点$L$,计算右端点的所有答案。

    设$mn=min[l,mid]$,$mx=max[l,mid]$

    令a为最大的位置使得$[mid+1,a]$的所有元素都大于$mn$

     b为最大的位置使得$[mid+1,a]$的所有元素都小于$mx$

    那么右端点被$a$,$b$两个位置分成三段,分类讨论。

    假设$a<b$,($a>b$的情况同理)。

    若$jleq a$,对答案有$mx*mn*sum_{j=mid+1}^a (j-i+1)$的贡献。

    若$a<jleq b$,对答案有$mx*(sum_{a+1}^b min[mid+1,j]*j - sum_{j=mid+1}^b min[mid+1,j]*(i-1))$

    若$b<jleq r$,对答案有$sum_{j=b+1}^r min[mid+1,j]*max[mid+1,j]*j - sum_{j=b+1}^r min[mid+1,r]*max[mid+1,r]*(i-1)$

    不难发现,上面的式子都是可以预处理的。

    $T(n)=2*T(n/2)+O(n)$,这东西是$O(nlogn)$的。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define M 500010
     4 #define MOD 1000000000
     5 #define inf 2147483647
     6 int a[M];
     7 int Ans;
     8 int mn[M], mx[M], mnj[M], mxj[M], mnmx[M], mnmxj[M];
     9 inline void Do(int l, int r) {
    10     if(l == r) {
    11         Ans += 1ll * a[l] * a[l] % MOD;
    12         if(Ans >= MOD) Ans -= MOD;
    13         return;
    14     }
    15     int mid = (l + r) / 2;
    16     Do(l, mid); Do(mid + 1, r);
    17     mn[mid] = mx[mid] = mnj[mid] = mxj[mid] = 0;
    18     mnmx[mid] = mnmxj[mid] = 0;
    19     int Max = 0, Min = inf;
    20     for(int i = mid + 1; i <= r; ++ i) {
    21         Max = max(Max, a[i]);
    22         Min = min(Min, a[i]);
    23         mn[i] = mn[i - 1] + Min;
    24         if(mn[i] >= MOD) mn[i] -= MOD;
    25         mx[i] = mx[i - 1] + Max;
    26         if(mx[i] >= MOD) mx[i] -= MOD;
    27         mnj[i] = mnj[i - 1] + 1ll * Min * i % MOD;
    28         if(mnj[i] >= MOD) mnj[i] -= MOD;
    29         mxj[i] = mxj[i - 1] + 1ll * Max * i % MOD;
    30         if(mxj[i] >= MOD) mxj[i] -= MOD;
    31         mnmx[i] = mnmx[i - 1] + 1ll * Max * Min % MOD;
    32         if(mnmx[i] >= MOD) mnmx[i] -= MOD;
    33         mnmxj[i] = mnmxj[i - 1] + 1ll * Max * Min % MOD * i % MOD;
    34         if(mnmxj[i] >= MOD) mnmxj[i] -= MOD;
    35     }
    36     Max = 0, Min = inf;
    37     int A = mid, B = mid;
    38     for(int i = mid; i >= l; -- i) {
    39         Max = max(Max, a[i]);
    40         Min = min(Min, a[i]);
    41         while(a[A + 1] >= Min && A < r) ++ A;
    42         while(a[B + 1] <= Max && B < r) ++ B;
    43         int aa = min(A, B), bb = max(A, B);
    44         Ans += 1ll * Min * Max % MOD * ((1ll * (mid + aa - i - i + 3) * (aa - mid) / 2ll) % MOD) % MOD;
    45         if(Ans >= MOD) Ans -= MOD;
    46         if(A < B) {
    47             Ans += 1ll * Max * ((mnj[bb] - mnj[aa] - 1ll * (i - 1) * (mn[bb] - mn[aa]) % MOD) % MOD + MOD) % MOD;
    48             if(Ans >= MOD) Ans -= MOD;
    49         }
    50         else {
    51             Ans += 1ll * Min * ((mxj[bb] - mxj[aa] - 1ll * (i - 1) * (mx[bb] - mx[aa]) % MOD) % MOD + MOD) % MOD;
    52             if(Ans >= MOD) Ans -= MOD;
    53         }
    54         Ans += (mnmxj[r] - mnmxj[bb]);
    55         if(Ans >= MOD) Ans -= MOD;
    56         if(Ans < 0) Ans += MOD;
    57         Ans += (MOD - (1ll * (i - 1) * (mnmx[r] - mnmx[bb] + MOD) % MOD));
    58         if(Ans >= MOD) Ans -= MOD;
    59     }
    60 }
    61 int main() {
    62     int n;
    63     scanf("%d", &n);
    64     for(int i = 1; i <= n; ++ i) {
    65         scanf("%d", &a[i]);
    66     }
    67     Do(1, n);
    68     printf("%d
    ", Ans);
    69 }
  • 相关阅读:
    vi/vim 如何添加和删除多行注释
    linux报错:命令未找到
    删除远程分支的方法
    k-vim常见快捷键
    [转]常见linux命令用法介绍
    python库termcolor用法
    gitignore样例解析
    [转]"git rm" 和 "rm" 的区别
    python中的slice用法
    牛客网linux试题-错误整理-20170914
  • 原文地址:https://www.cnblogs.com/iamqzh233/p/9452345.html
Copyright © 2020-2023  润新知