Description
Solution
考虑分治,假设我们现在分治到区间 [l,r] [ l , r ] ,区间中点为 mid m i d ,那么只要计算跨过中间的区间的贡献即可。
我们用一个
x
x
从向
l
l
枚举,设。
我们维护两个指针
p,q
p
,
q
从
mid
m
i
d
向右移动,
p
p
维护最右到哪个位置满足;同理,
q
q
维护最右到哪个位置满足。
对于当前的左端点
x
x
,我们将右区间分为段(这里假设
p≤q
p
≤
q
,
q<p同理
q
<
p
同
理
):
1. 对于
y≤p
y
≤
p
,最小值为
A
A
,最大值为,可直接求和。
2. 对于
p<y≤q
p
<
y
≤
q
,最大值为
B
B
,最小值未知,我们要算的贡献是:。我们预处理出
maxi=mid+1yai,maxi=mid+1yi×ai
max
i
=
m
i
d
+
1
y
a
i
,
max
i
=
m
i
d
+
1
y
i
×
a
i
的前缀和即可。
(同理要预处理
mini=mid+1yai,mini=mid+1yi×ai
min
i
=
m
i
d
+
1
y
a
i
,
min
i
=
m
i
d
+
1
y
i
×
a
i
的前缀和)
3.
q<y
q
<
y
时,贡献为
∑y=q+1r(y−x+1))maxi=mid+1yaimini=mid+1yai
∑
y
=
q
+
1
r
(
y
−
x
+
1
)
)
max
i
=
m
i
d
+
1
y
a
i
min
i
=
m
i
d
+
1
y
a
i
,我们预处理出
maxi=mid+1yaimini=mid+1yai
max
i
=
m
i
d
+
1
y
a
i
min
i
=
m
i
d
+
1
y
a
i
和
maxi=mid+1yaimini=mid+1yai×i
max
i
=
m
i
d
+
1
y
a
i
min
i
=
m
i
d
+
1
y
a
i
×
i
的前缀和即可。
Solution
/************************************************
* Au: Hany01
* Date: Aug 17th, 2018
* Prob: BZOJ3745 COCI2015 Norma
* Email: hany01@foxmail.com
* Inst: Yali High School
************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
static int _, __; static char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 5e5 + 3, MOD = 1e9;
int n, a[maxn], mn[maxn], mx[maxn], mnid[maxn], mxid[maxn], mnmx[maxn], mnmxid[maxn], Ans;
inline int ad(int x, int y) { if ((x += y) >= MOD) return x - MOD; return x; }
void DivideAndConquer(int l, int r)
{
if (l == r) { Ans = ad(Ans, (LL)a[l] * a[l] % MOD); return; }
int mid = (l + r) >> 1;
DivideAndConquer(l, mid), DivideAndConquer(mid + 1, r);
register int p = mid, q = mid, A = INF, B = -INF, minpq, maxpq, Min = INF, Max = -INF;
mn[mid] = mnid[mid] = mx[mid] = mxid[mid] = mnmx[mid] = mnmxid[mid] = 0;
For(i, mid + 1, r) {
chkmin(Min, a[i]), chkmax(Max, a[i]);
mn[i] = ad(mn[i - 1], Min), mnid[i] = ad(mnid[i - 1], (LL)Min * i % MOD);
mx[i] = ad(mx[i - 1], Max), mxid[i] = ad(mxid[i - 1], (LL)Max * i % MOD);
mnmx[i] = ad(mnmx[i - 1], (LL)Min * Max % MOD), mnmxid[i] = ad(mnmxid[i - 1], (LL)Min * Max % MOD * i % MOD);
}
Fordown(x, mid, l) {
chkmax(B, a[x]), chkmin(A, a[x]);
while (p < r && a[p + 1] >= A) ++ p;
while (q < r && a[q + 1] <= B) ++ q;
minpq = min(p, q), maxpq = max(p, q);
if (mid < minpq) Ans = ad(Ans, (LL)(mid + 1 - x + 1 + minpq - x + 1) * (minpq - mid) / 2 % MOD * A % MOD * B % MOD);
if (minpq < maxpq) {
if (p < q) Ans = ad(Ans, (LL)B * ad(ad(mnid[maxpq], MOD - mnid[minpq]), MOD - (LL)ad(mn[maxpq], MOD - mn[minpq]) * (x - 1) % MOD) % MOD);
else Ans = ad(Ans, (LL)A * ad(ad(mxid[maxpq], MOD - mxid[minpq]), MOD - (LL)ad(mx[maxpq], MOD - mx[minpq]) * (x - 1) % MOD) % MOD);
}
Ans = ad(Ans, ad(ad(mnmxid[r], MOD - mnmxid[maxpq]), MOD - (LL)(x - 1) * ad(mnmx[r], MOD - mnmx[maxpq]) % MOD));
}
}
int main()
{
#ifdef hany01
freopen("bzoj3745.in", "r", stdin);
freopen("bzoj3745.out", "w", stdout);
#endif
For(i, 1, n = read()) a[i] = read();
DivideAndConquer(1, n), printf("%d\n", Ans);
return 0;
}