题目大意:
n
<
=
500000
,
0
<
=
A
[
i
]
<
=
1
0
9
n<=500000,0<=A[i]<=10^9
n<=500000,0<=A[i]<=109
分析:
显然直接枚举区间时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),不能接受
那么我们可以考虑分治,
那么区间
[
1
,
n
]
[1,n]
[1,n]就会被分成多块
即 (以下
/
2
/2
/2均为向下取整)
[
1
,
n
]
[1,n]
[1,n]
[
1
,
(
n
+
1
)
/
2
]
[1,(n+1)/2]
[1,(n+1)/2],
[
(
n
+
1
)
/
2
+
1
,
n
]
[(n+1)/2+1,n]
[(n+1)/2+1,n]
…
[
1
,
1
]
[1,1]
[1,1],
[
2
,
2
]
[2,2]
[2,2],…,
[
n
,
n
]
[n,n]
[n,n]
那么我们可以发现如果要使得不重复计算贡献的话,
一个区间
[
l
,
r
]
[l,r]
[l,r]的总贡献为
所有过其中点
m
i
d
mid
mid且任一端点不为
m
i
d
mid
mid的子区间的(
区
间
m
a
x
∗
m
i
n
区间max*min
区间max∗min)之和
即
[
l
,
m
i
d
+
1
]
,
[
l
,
m
i
d
+
2
]
,
.
.
.
,
[
l
,
r
]
[l,mid+1],[l,mid+2],...,[l,r]
[l,mid+1],[l,mid+2],...,[l,r]的,
[
l
+
1
,
m
i
d
+
1
]
,
[
l
+
1
,
m
i
d
+
2
]
,
.
.
.
,
[
l
+
1
,
r
]
[l+1,mid+1],[l+1,mid+2],...,[l+1,r]
[l+1,mid+1],[l+1,mid+2],...,[l+1,r]的,
…
[
m
i
d
−
2
,
m
i
d
+
1
]
,
[
m
i
d
−
2
,
m
i
d
+
2
]
,
.
.
.
,
[
m
i
d
−
2
,
r
]
[mid-2,mid+1],[mid-2,mid+2],...,[mid-2,r]
[mid−2,mid+1],[mid−2,mid+2],...,[mid−2,r]的,
[
m
i
d
−
1
,
m
i
d
+
1
]
,
[
m
i
d
−
1
,
m
i
d
+
2
]
,
.
.
.
,
[
m
i
d
−
1
,
r
]
[mid-1,mid+1],[mid-1,mid+2],...,[mid-1,r]
[mid−1,mid+1],[mid−1,mid+2],...,[mid−1,r]的区间
m
a
x
∗
m
i
n
max*min
max∗min之和
对于一段区间
[
l
,
r
]
[l,r]
[l,r]的贡献求解方面,
设
m
a
x
i
max_i
maxi表示
[
m
i
d
+
1
,
i
]
[mid+1,i]
[mid+1,i]中
a
i
a_i
ai的最大值(
i
>
m
i
d
i>mid
i>mid)
m
i
n
i
min_i
mini同理求最小值
s
u
m
m
a
x
i
summax_i
summaxi表示
m
a
x
i
max_i
maxi在
[
m
i
d
+
1
,
i
]
[mid+1,i]
[mid+1,i]的和
s
u
m
m
i
n
i
summin_i
summini同理表示
m
i
n
i
min_i
mini的
s
u
m
c
j
i
sumcj_i
sumcji表示
m
a
x
i
∗
m
i
n
i
max_i*min_i
maxi∗mini在
[
m
i
d
+
1
,
1
]
[mid+1,1]
[mid+1,1]的和
这些可以在
O
(
r
−
m
i
d
)
O(r-mid)
O(r−mid)内处理完
然后我们枚举左端点
L
L
L,
L
L
L从
m
i
d
−
1
mid-1
mid−1开始
c
m
a
x
cmax
cmax为
[
L
,
m
i
d
]
[L,mid]
[L,mid]中
m
a
x
(
a
i
)
max(a_i)
max(ai)
c
m
i
n
cmin
cmin为
[
L
,
m
i
d
]
[L,mid]
[L,mid]中
m
i
n
(
a
i
)
min(a_i)
min(ai)
另设
p
p
p为
[
m
i
d
+
1
,
r
]
[mid+1,r]
[mid+1,r]中第一个满足
a
p
+
1
<
c
m
i
n
a_{p+1}<cmin
ap+1<cmin的,不存在时
p
=
r
p=r
p=r
q
q
q为
[
m
i
d
+
1
,
r
]
[mid+1,r]
[mid+1,r]中第一个满足
a
q
+
1
>
c
m
a
x
a_{q+1}>cmax
aq+1>cmax的,不存在时
q
=
r
q=r
q=r
那么我们就可以分类讨论了,
我们钦定
p
<
q
p<q
p<q,
①
区
间
[
m
i
d
+
1
,
p
]
①区间[mid+1,p]
①区间[mid+1,p]:
此时并没有到
p
+
1
p+1
p+1,更没有到
q
+
1
q+1
q+1,
那么显然所有
[
L
,
R
]
[L,R]
[L,R]
(
R
∈
[
m
i
d
+
1
,
p
]
)
(R∈[mid+1,p])
(R∈[mid+1,p])的最大值和最小值都是
c
m
a
x
,
c
m
i
n
cmax,cmin
cmax,cmin,
他们的总贡献为
c
m
a
x
∗
c
m
i
n
∗
(
p
−
(
m
i
d
+
1
)
+
1
)
cmax*cmin*(p-(mid+1)+1)
cmax∗cmin∗(p−(mid+1)+1)
②
区
间
[
p
+
1
,
q
]
②区间[p+1,q]
②区间[p+1,q]:
此时已经经过了
p
+
1
p+1
p+1,所以
[
L
,
R
]
[L,R]
[L,R]
(
R
∈
[
p
+
1
,
q
]
)
(R∈[p+1,q])
(R∈[p+1,q])中
因为没有到
q
+
1
q+1
q+1,所以最大值依然是
c
m
a
x
cmax
cmax,
但是最小值已经不在
[
l
,
p
]
[l,p]
[l,p]中,而应该在
[
p
+
1
,
q
]
[p+1,q]
[p+1,q]中,但是我们并不能确定每在
[
p
+
1
,
q
]
[p+1,q]
[p+1,q]中经过一个点,它的最小值是否会变,所以我们一开始就预处理了一个最小值的前缀和,
对于
c
m
a
x
∗
最
小
值
1
+
c
m
a
x
∗
最
小
值
2
.
.
.
+
c
m
a
x
∗
最
小
值
x
cmax*最小值_1+cmax*最小值_2...+cmax*最小值_x
cmax∗最小值1+cmax∗最小值2...+cmax∗最小值x而言,
就为
c
m
a
x
∗
最
小
值
之
和
cmax*最小值之和
cmax∗最小值之和
那么他们的总贡献为
c
m
a
x
∗
最
小
值
总
和
cmax*最小值总和
cmax∗最小值总和,即
c
m
a
x
∗
(
s
u
m
m
i
n
q
−
s
u
m
(
p
+
1
)
−
1
)
cmax*(summin_q-sum_{(p+1)-1})
cmax∗(summinq−sum(p+1)−1)
③
[
q
+
1
,
r
]
③[q+1,r]
③[q+1,r]
此时已经经过了
p
+
1
p+1
p+1,
q
+
1
q+1
q+1,所以
[
L
,
R
]
[L,R]
[L,R]
(
R
∈
[
q
+
1
,
r
]
)
(R∈[q+1,r])
(R∈[q+1,r])中
最小值,最大值已经不取决于区间
[
L
,
q
]
[L,q]
[L,q]了,
此时我们就是用到一开始预处理的
s
u
m
c
j
i
sumcj_i
sumcji了,
即贡献为
Σ
i
=
q
+
1
r
m
a
x
i
∗
m
i
n
i
(
m
a
x
i
,
m
i
n
i
此
时
肯
定
比
c
m
a
x
,
c
m
i
n
优
)
Σ_{i=q+1}^{r}max_i*min_i(max_i,min_i此时肯定比cmax,cmin优)
Σi=q+1rmaxi∗mini(maxi,mini此时肯定比cmax,cmin优)
即为
s
u
m
c
j
r
−
s
u
m
c
j
(
q
+
1
)
−
1
sumcj_{r}-sumcj_{(q+1)-1}
sumcjr−sumcj(q+1)−1
q
<
p
q<p
q<p同理时候好像就是第二步换了一下位置
一开始用了 O ( 1 ) O(1) O(1)快速乘,结果常数大 T T T了 4 , 5 4,5 4,5个点。。后来发现 l o n g l o n g longlong longlong炸不了,然后取模可能出现的负数要处理一下。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#define inf 0x7fffffff
#define N 500005
using namespace std;
typedef long long ll;
ll maxnum[N], minnum[N], summax[N], summin[N], sumcj[N], a[N], Answer;
int n, modn = 1000000007;
void read(ll &x)
{
ll f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = - 1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
x = x * f;
}
void Work(int l, int r)
{
if (l == r) { Answer = ((Answer + a[l] * a[l] % modn) % modn + modn) % modn; return; }
int mid = (l + r) >> 1;
Work(l, mid); Work(mid + 1, r);
maxnum[mid] = summax[mid] = 0;
minnum[mid] = inf, summin[mid] = 0;
sumcj[mid] = 0;
for (int i = mid + 1; i <= r; i++)
{
maxnum[i] = max(maxnum[i - 1], a[i]), summax[i] = (summax[i - 1] + maxnum[i]) % modn;
minnum[i] = min(minnum[i - 1], a[i]), summin[i] = (summin[i - 1] + minnum[i]) % modn;
sumcj[i] = ((sumcj[i - 1] + maxnum[i] * minnum[i] % modn) % modn + modn) % modn;
}
ll max_cdp = 0, min_cdp = inf;
int p = mid, q = mid;
for (int i = mid; i >= l; i--)
{
max_cdp = max(max_cdp, a[i]);
min_cdp = min(min_cdp, a[i]);
while (a[p + 1] >= min_cdp && p < r) p++;
while (a[q + 1] <= max_cdp && q < r) q++;
if (p < q) Answer = ((Answer + max_cdp * min_cdp % modn * (p - mid) % modn + (summin[q] - summin[p]) * max_cdp % modn + (sumcj[r] - sumcj[q])) % modn + modn) % modn;
else Answer = ((Answer + max_cdp * min_cdp % modn * (q - mid) % modn + (summax[p] - summax[q]) * min_cdp % modn + (sumcj[r] - sumcj[p])) % modn + modn) % modn;
}
}
int main()
{
freopen("seq.in", "r", stdin);
freopen("seq.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) read(a[i]);
Work(1, n);
printf("%lld\n", Answer);
return 0;
}