题目大意:
分析:
显然直接枚举区间时间复杂度为
,不能接受
那么我们可以考虑分治,
那么区间
就会被分成多块
即 (以下
均为向下取整)
,
…
,
,…,
那么我们可以发现如果要使得不重复计算贡献的话,
一个区间
的总贡献为
所有过其中点
且任一端点不为
的子区间的(
)之和
即
的,
的,
…
的,
的区间
之和
对于一段区间
的贡献求解方面,
设
表示
中
的最大值(
)
同理求最小值
表示
在
的和
同理表示
的
表示
在
的和
这些可以在
内处理完
然后我们枚举左端点
,
从
开始
为
中
为
中
另设
为
中第一个满足
的,不存在时
为
中第一个满足
的,不存在时
那么我们就可以分类讨论了,
我们钦定
,
:
此时并没有到
,更没有到
,
那么显然所有
的最大值和最小值都是
,
他们的总贡献为
:
此时已经经过了
,所以
中
因为没有到
,所以最大值依然是
,
但是最小值已经不在
中,而应该在
中,但是我们并不能确定每在
中经过一个点,它的最小值是否会变,所以我们一开始就预处理了一个最小值的前缀和,
对于
而言,
就为
那么他们的总贡献为
,即
此时已经经过了
,
,所以
中
最小值,最大值已经不取决于区间
了,
此时我们就是用到一开始预处理的
了,
即贡献为
即为
同理时候好像就是第二步换了一下位置
一开始用了 快速乘,结果常数大 了 个点。。后来发现 炸不了,然后取模可能出现的负数要处理一下。
代码:
#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;
}