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$的情况同理)。
若$j\leq a$,对答案有$mx*mn*\sum_{j=mid+1}^a (j-i+1)$的贡献。
若$a<j\leq b$,对答案有$mx*(\sum_{a+1}^b min[mid+1,j]*j - \sum_{j=mid+1}^b min[mid+1,j]*(i-1))$
若$b<j\leq 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\n", Ans); 69 }