• 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 }
  • 相关阅读:
    SQL_Server_2005_数据类型转换函数(描述及实例)
    讨论:GUID与int自增列的问题
    SQL Server 2005无日志文件附加数据库
    优化SQL查询:如何写出高性能SQL语句
    开源项目之视频会议程序 Omnimeeting
    wzplayer player (android,windows,ios) 多核解码
    利用office2010 word2010生成目录
    利用office2010 word2010生成目录
    最近在忙活视频通话(sip)
    介绍几个在线画流程图的工具
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7610908.html
Copyright © 2020-2023  润新知