BZOJ3745 COCI2015Norma(分治)

  完全想不到地,考虑分治。

  对区间[l,r],将左端点x由mid不断左移,右边记录最右的p满足max[mid+1,p]<=max[x,mid],q满足min[mid+1,q]>=min[x,mid]。这样右边被分成三部分,分别统计。

  对于p和q左边的位置,这部分的max和min显然是由左边部分决定的,答案非常好算。

  对于p和q右边的位置,这部分的max和min显然是由右边部分决定的,可以在分治的一开始预处理一个右区间的前缀len*max*min和max*min,这样就很好算了。

  对于p和q中间的位置,若p在q左边,则这一部分最小值是由左边决定的,而最大值是由右边决定的,预处理右区间前缀len*max和max;反之同理。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 500010
#define P 1000000000
int n,a[N],lenmaxmin[N],maxmin[N],lenmax[N],lenmin[N],MAX[N],MIN[N],ans;
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
void solve(int l,int r)
{
    if (l==r) {inc(ans,1ll*a[l]*a[l]%P);return;}
    int mid=l+r>>1;
    solve(l,mid),solve(mid+1,r);
    int mx=0,mn=P,p=mid,q=mid;
    lenmaxmin[mid]=maxmin[mid]=lenmax[mid]=lenmin[mid]=MAX[mid]=MIN[mid]=0;
    for (int i=mid+1;i<=r;i++)
    {
        mx=max(mx,a[i]),mn=min(mn,a[i]);
        lenmaxmin[i]=(lenmaxmin[i-1]+1ll*(i-mid)*mx%P*mn%P)%P;
        maxmin[i]=(maxmin[i-1]+1ll*mx*mn%P)%P;
        lenmax[i]=(lenmax[i-1]+1ll*(i-mid)*mx%P)%P;
        lenmin[i]=(lenmin[i-1]+1ll*(i-mid)*mn%P)%P;
        MAX[i]=(MAX[i-1]+mx)%P;
        MIN[i]=(MIN[i-1]+mn)%P;
    }
    mx=0,mn=P;
    for (int i=mid;i>=l;i--)
    {
        mx=max(mx,a[i]),mn=min(mn,a[i]);
        while (p<r&&a[p+1]<=mx) p++;
        while (q<r&&a[q+1]>=mn) q++;
        inc(ans,((1ll*((mid-i+2+min(p,q)-i+1)%P)*(min(p,q)-mid)>>1)+P)%P*mx%P*mn%P);
        inc(ans,(1ll*(maxmin[r]-maxmin[max(p,q)]+P)*(mid-i+1)+lenmaxmin[r]-lenmaxmin[max(p,q)]+P)%P);
        if (p<q) inc(ans,(1ll*(MAX[q]-MAX[p]+P)*(mid-i+1)+lenmax[q]-lenmax[p]+P)%P*mn%P);
        else inc(ans,(1ll*(MIN[p]-MIN[q]+P)*(mid-i+1)+lenmin[p]-lenmin[q]+P)%P*mx%P);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj3745.in","r",stdin);
    freopen("bzoj3745.out","w",stdout);
#endif
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    solve(1,n);
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/Gloid/p/9738968.html