bzoj3745 [Coci2015]Norma

Description

Input

第1行,一个整数N;
第2~n+1行,每行一个整数表示序列a。 

Output

输出答案对10^9取模后的结果。

Sample Input

4
2
4
1
4

Sample Output

109
【数据范围】
N <= 500000
1 <= a_i <= 10^8
 
正解:分治。
考虑用分治来处理这个问题。我们在分治时,可以把横跨$mid$的区间计算出来,然后再递归算左右子区间。
我们可以固定左端点,然后统一计算右端点取不同位置的贡献。
可以发现,有$3$种情况:最小值和最大值都在左侧,最小值或最大值有一个在右侧,最小值和最大值都在右侧。
在左端点往左移动的时候,上面$3$中情况形成的区间是依次连续且单调的,只会慢慢往右移。
于是我们可以维护两个单调指针,记录$3$个区间的中间两个端点。
然后统计答案也不难,我们直接把式子拆开,发现只要维护几个前缀和就行了。
 
 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define rhl (1000000000)
 6 #define N (500010)
 7 
 8 using namespace std;
 9 
10 int a[N],Min[N],Max[N],smin[N],smax[N],spmin[N],spmax[N],minmax[N],sminmax[N],n,ans;
11 
12 il int gi(){
13   RG int x=0,q=1; RG char ch=getchar();
14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
15   if (ch=='-') q=-1,ch=getchar();
16   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
17   return q*x;
18 }
19 
20 il int calc(RG int n){ return (1LL*n*(n+1)>>1)%rhl; }
21 
22 il void solve(RG int l,RG int r){
23   if (l==r){ ans=(ans+1LL*a[l]*a[r])%rhl; return; } RG int mid=(l+r)>>1;
24   Min[mid]=Max[mid]=a[mid],Min[mid+1]=Max[mid+1]=a[mid+1];
25   for (RG int i=mid-1;i>=l;--i) Min[i]=min(Min[i+1],a[i]),Max[i]=max(Max[i+1],a[i]);
26   for (RG int i=mid+2;i<=r;++i) Min[i]=min(Min[i-1],a[i]),Max[i]=max(Max[i-1],a[i]);
27   smin[mid]=smax[mid]=spmin[mid]=spmax[mid]=minmax[mid]=sminmax[mid]=0;
28   for (RG int i=mid+1;i<=r;++i){
29     smin[i]=smin[i-1]+Min[i]; if (smin[i]>=rhl) smin[i]-=rhl;
30     smax[i]=smax[i-1]+Max[i]; if (smax[i]>=rhl) smax[i]-=rhl;
31     spmin[i]=(spmin[i-1]+1LL*(i+1)*Min[i])%rhl;
32     spmax[i]=(spmax[i-1]+1LL*(i+1)*Max[i])%rhl;
33     minmax[i]=(minmax[i-1]+1LL*Min[i]*Max[i])%rhl;
34     sminmax[i]=(sminmax[i-1]+1LL*Min[i]*Max[i]%rhl*(i+1))%rhl;
35   }
36   for (RG int i=mid,j=mid+1,k=mid+1;i>=l;--i){
37     while (j<=r && Min[i]<=Min[j] && Max[i]>=Max[j]) ++j;
38     while (k<=r && (Min[i]<=Min[k] || Max[i]>=Max[k])) ++k;
39     ans=(ans+1LL*Min[i]*Max[i]%rhl*(calc(j-i)-calc(mid-i+1)+rhl))%rhl; if (j>r) continue;
40     if (Min[i]<=Min[j] && Max[i]<Max[j])
41       ans=(ans+1LL*Min[i]*(spmax[k-1]-spmax[j-1])-1LL*i*Min[i]%rhl*(smax[k-1]-smax[j-1]))%rhl;
42     if (Min[i]>Min[j] && Max[i]>=Max[j])
43       ans=(ans+1LL*Max[i]*(spmin[k-1]-spmin[j-1])-1LL*i*Max[i]%rhl*(smin[k-1]-smin[j-1]))%rhl;
44     if (k>r) continue; ans=(ans+sminmax[r]-sminmax[k-1]-1LL*i*(minmax[r]-minmax[k-1]))%rhl;
45   }
46   solve(l,mid),solve(mid+1,r); return;
47 }
48 
49 int main(){
50 #ifndef ONLINE_JUDGE
51   freopen("norma.in","r",stdin);
52   freopen("norma.out","w",stdout);
53 #endif
54   n=gi(); for (RG int i=1;i<=n;++i) a[i]=gi();
55   solve(1,n),cout<<(ans%rhl+rhl)%rhl; return 0;
56 }

 

posted @ 2017-09-29 14:36  wfj_2048  阅读(184)  评论(0编辑  收藏  举报