博客园 首页 私信博主 显示目录 隐藏目录 管理

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;
}

posted @ 2017-12-22 20:20  ck666  阅读(187)  评论(0编辑  收藏  举报