bzoj 3745: [Coci2015]Norma
Description
给定序列\(a_i\)
求
\[\sum_{i=1}^n \sum_{j=i}^n (j-i+1)\max\{a_i,a_{i+1}\cdots a_j\}\min\{a_i,a_{i+1}\cdots a_j\}
\]
Input
第1行,一个整数N;
第2~n+1行,每行一个整数表示序列a。
Output
输出答案对10^9取模后的结果。
Sample Input
4
2 4 1 4
Sample Output
109
【数据范围】
\(N \le 500000\)
\(1 \le a_i \le 10^8\)
我还有什么话可以说呢,都是细节问题。细节什么的最讨厌了
维护前缀\(sum1,sum2,sum3\)分别是\([0]\)里记录前缀中每一个数的\(a_i*i\)后的和,\([1]\)里记录每一个数在区间里的前缀和,这样求一个区间的贡献可以表示成\(sum[i][0]-sum[i][1]*j\)
\(j\)是当前点的编号,于是这样玄学的复杂度>_<
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define ll long long
inline ll read(){
ll an=0;
char ch=getchar();
while(ch<'0'||ch>'9'){ch=getchar();}
while('0'<=ch&&ch<='9'){an=an*10+(ch^48);ch=getchar();}
return an;
}
const ll mod=1e9;
const ll MAXn=500000+2333;
ll ans;
ll n;
ll sum1[MAXn][2],sum2[MAXn][2],sum3[MAXn][3],a[MAXn];
/*
\sum_{i=1}^n\sum_{j=i}^n(j-i+1)
\MAX\{a_i,a_{i+1}\cdots a_j\}
\MIN\{a_i,a_{i+1}\cdots a_j\}
*/
inline void prepare(){
n=read();
for(ll i=1;i<=n;i++)a[i]=read();
}
inline void solve(ll l,ll r){
ll mid=l+r>>1;
if(l==r){
ans=(ans%mod+a[l]*a[l]%mod)%mod;
return;
}
sum1[mid][0]=sum1[mid][1]=0;
sum2[mid][0]=sum2[mid][1]=0;
sum3[mid][0]=sum3[mid][1]=0;
ll ma=-1,mi=1e9;
for(ll i=mid+1;i<=r;i++){
ma=max(ma,a[i]);
mi=min(mi,a[i]);
sum1[i][0]=ma%mod*mi%mod*i%mod;
sum1[i][1]=ma*mi%mod;
sum2[i][0]=mi*i%mod;sum2[i][1]=mi;
sum3[i][0]=ma*i%mod;sum3[i][1]=ma;
sum1[i][0]=(sum1[i][0]+sum1[i-1][0])%mod;
sum1[i][1]=(sum1[i][1]+sum1[i-1][1])%mod;
sum2[i][0]=(sum2[i][0]+sum2[i-1][0])%mod;
sum2[i][1]=(sum2[i][1]+sum2[i-1][1])%mod;
sum3[i][0]=(sum3[i][0]+sum3[i-1][0])%mod;
sum3[i][1]=(sum3[i][1]+sum3[i-1][1])%mod;
}
ma=-1,mi=1e9;
ll t1=a[mid+1],t2=a[mid+1];
ll p1=mid,p2=mid;
for(ll i=mid;i>=l;i--){
ma=max(ma,a[i]);
mi=min(a[i],mi);
while(t1>=mi&&p1<r)p1++,t1=min(t1,a[p1+1]);
while(t2<=ma&&p2<r)p2++,t2=max(t2,a[p2+1]);
ll tmp;
tmp=min(p1,p2);
ll wi=(mid+2-i+tmp-i+1)*(tmp-mid)/2;
ans=(ans+wi%mod*ma%mod*mi)%mod;
tmp=max(p1,p2)+1;
wi=sum1[r][0]-sum1[tmp-1][0];
wi=(wi-(sum1[r][1]-sum1[tmp-1][1])%mod*(i-1))%mod;
ans=(ans%mod+wi)%mod;
if(p1<=p2){
wi=(sum2[p2][0]-sum2[p1][0])%mod*ma%mod;
wi=(wi-(sum2[p2][1]-sum2[p1][1])%mod*(i-1)%mod*ma+mod)%mod;
ans=(ans+wi)%mod;
}
else{
wi=(sum3[p1][0]-sum3[p2][0])%mod*mi;
wi=(wi-(sum3[p1][1]-sum3[p2][1])%mod*(i-1)%mod*mi%mod+mod)%mod;
ans=(ans+wi)%mod;
}
}
solve(l,mid);
solve(mid+1,r);
ans=(ans%mod+mod)%mod;
}
int main(){
prepare();
solve(1,n);
cout<<ans<<"\n";
return 0;
}