考虑分治,对于区间[l,r],计算左端点在[l,mid],右端点在[mid,r]的区间对答案的影响
然后自己推公式。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (LL j=k;j<=l;++j)
#define red(j,k,l) for (LL j=k;j>=l;--j)
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define LL long long
#define mod 1000000000
#define N 500005
using namespace std;
LL a[N],n,ans,mx[N],mn[N],sx[N],sn[N],p[N];
void solve(LL l,LL r){
if (l>r) return;
if (l==r){ ans=(ans+a[l]*a[r])%mod; return; }
LL mid=l+r>>1;
solve(l,mid-1);solve(mid+1,r);
LL Mx,Mn,nx,nm;
mx[mid]=a[mid];rep(i,mid+1,r) mx[i]=max(a[i],mx[i-1]);red(i,mid-1,l) mx[i]=max(a[i],mx[i+1]);
mn[mid]=a[mid];rep(i,mid+1,r) mn[i]=min(a[i],mn[i-1]);red(i,mid-1,l) mn[i]=min(a[i],mn[i+1]);
sx[mid]=a[mid];rep(i,mid+1,r) sx[i]=(sx[i-1]+mx[i])%mod;red(i,mid-1,l) sx[i]=(sx[i+1]+mx[i])%mod;
sn[mid]=a[mid];rep(i,mid+1,r) sn[i]=(sn[i-1]+mn[i])%mod;red(i,mid-1,l) sn[i]=(sn[i+1]+mn[i])%mod;
p[mid]=a[mid]*a[mid]%mod;rep(i,mid+1,r) p[i]=(p[i-1]+mx[i]*mn[i])%mod;red(i,mid-1,l) p[i]=(p[i+1]+mx[i]*mn[i])%mod;
Mx=mid,Mn=mid,nx=a[mid],nm=a[mid];
red(i,mid,l){
LL A=0;nx=max(nx,a[i]);nm=min(nm,a[i]);
while (Mx<r&&mx[Mx+1]<=nx) Mx++;while (Mn<r&&mn[Mn+1]>=nm) Mn++;
if (Mx==Mn) A=(nx*nm%mod*(Mx-mid+1)%mod+p[r]-p[Mx]+mod)%mod;
else if (Mx<Mn) A=(nx*nm%mod*(Mx-mid+1)+(sx[Mn]-sx[Mx]+mod)*nm+p[r]-p[Mn]+mod)%mod;
else A=(nx*nm%mod*(Mn-mid+1)+(sn[Mx]-sn[Mn]+mod)*nx+p[r]-p[Mx]+mod)%mod;
//printf("%lld %lld\n",Mx,Mn);
ans=(ans+(1-i)*A%mod+mod)%mod;
//printf("-!-%lld\n",ans);
//printf("----%lld %lld %lld %lld\n",l,r,ans,A);
}
Mx=mid,Mn=mid,nx=a[mid],nm=a[mid];
rep(i,mid,r){
LL A=0;nx=max(nx,a[i]);nm=min(nm,a[i]);
while (Mx>l&&mx[Mx-1]<=nx) Mx--;while (Mn>l&&mn[Mn-1]>=nm) Mn--;
if (Mx==Mn) A=(nx*nm%mod*(mid-Mx+1)%mod+p[l]-p[Mx]+mod)%mod;
else if (Mx>Mn) A=(nx*nm%mod*(mid-Mx+1)+(sx[Mn]-sx[Mx]+mod)*nm+p[l]-p[Mn]+mod)%mod;
else A=(nx*nm%mod*(mid-Mn+1)+(sn[Mx]-sn[Mn]+mod)*nx+p[l]-p[Mx]+mod)%mod;
ans=(ans+i*A%mod)%mod;
//printf("-*-%lld\n",ans);
//printf("----%lld %lld %lld %lld\n",l,r,ans,A);
}
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
scanf("%lld",&n);
rep(i,1,n) scanf("%lld",a+i);
solve(1,n);
printf("%lld\n",ans);
system("pause");
}