题意

给定一个正整数序列 \(a_1, a_2, \cdots, a_n\) ,求

\[\sum_{i=1}^{n} \sum_{j=i}^{n} (j - i + 1) \min(a_i,a_{i+1},\cdots,a_j) \max(a_i,a_{i+1},\cdots,a_j) \pmod {10^9}
\]

\(n \le 5\times 10^5, a_i \le 10^9\)

题解

对于这种求一段区间内所有子区间答案和的东西,我们常常可以考虑分治解决。

通常思路是这样的:

假设我们计算 \([l, r]\) 这段区间的答案和。令 \(\displaystyle mid = \lfloor \frac{l + r}{2} \rfloor\) 。

我们分治计算全在 \([l, mid]\) 以及 \([mid + 1, r]\) 区间的答案。

然后计算跨过 \(mid\) 的区间的答案。也就是左端点在 \([l, mid]\) 并且右端点在 \([mid + 1, r]\) 中的区间。

最后所有区间答案加起来就行了,正确性是显而易见的,因为一个区间要么全在左边,要么全在右边,要么跨过中点。

接下来难点就在跨过区间的答案计算上。

通常的话我们可以枚举一个端点,快速计算另外一个端点的贡献。

首先可以从 \(mid\) 到 \(l\) 枚举这个区间的左端点 \(x\) ,令 \([x, mid]\) 的最小值为 \(a\) ,最大值为 \(b\) 。

两个单调指针 \(p,q\) 从 \(mid\) 向右走(最多到 \(r\) ),分别指向使得 \([mid/x, i]\) 最小值/最大值 为 \(a\) / \(b\) 的最大位置 \(i\) 。

我们把区间右端点 \(y\) 分三种情况讨论。

  1. 对于 \(y \in [mid + 1, \min \{p, q\}]\) 这一部分 \(\min = a, \max = b\) 。那么答案就是

    \[\sum_{y=mid+1}^{ \min \{p, q\}} (y - x + 1) \times a \times b
    \]

    这部分用高斯求和优化即可。

  2. 对于 \(y \in (\min \{p, q\}, \max \{p, q\}]\) 这部分,会有两种情况,本质是一样的。

    我们讨论 \(p < q\) 这种,那么答案就是

    \[\sum_{y=\min \{p, q\}+1}^{\max \{p, q\}} (\min_{k = mid}^{y} a_k) \times(y - x + 1) \times b
    \]

    我们可以考虑预处理 \(\displaystyle \sum_{y=1}^{n} (\min_{k = mid}^{y}a_k)~y\) 以及 \(\displaystyle \sum_{y=1}^{n} (\min_{k = mid}^{y}a_k)\) 就行了。那么每次计算就是前缀和相减,然后乘上系数就行了。

  3. 对于最后一部分 \(y \in (\max \{p, q\}, r]\) ,那么我们类似与上面那个式子处理

    \[\sum_{y=\max \{p, q\}+1}^{r} (\min_{k = mid}^{y} a_k) (\max_{k = mid}^{y} a_k) \times(y - x + 1)
    \]

    那么我们只需要考虑预处理 \(\displaystyle \sum_{y=1}^{n}(\min_{k = mid}^{y} a_k)(\max_{k = mid}^{y} a_k)~y\) 以及 \(\displaystyle \sum_{y=1}^{n}(\min_{k = mid}^{y} a_k)(\max_{k = mid}^{y} a_k)\) ,类似于上面那个式子前缀和相减就行了。

然后这样就可以做完了,每次操作只需要扫一遍区间,所以复杂度就是 \(O(n \log n)\) 的。

总结

考虑所有子区间答案,或者所有点对的答案,可以尝试考虑分治。

然后继续考虑枚举一个端点,另外一个端点用一些特殊结构快速计算就行了。

代码

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
} void File() {
#ifdef zjp_shadow
freopen ("3745.in", "r", stdin);
freopen ("3745.out", "w", stdout);
#endif
} const int N = 5e5 + 1e3, inf = 0x7f7f7f7f, Mod = 1e9; int n, a[N]; int ans = 0; int Sum(int l, int r) { return (1ll * (r - l + 1) * (r + l) / 2) % Mod; } int SMM[N], SMMP[N], SMax[N], SMin[N], SMaxp[N], SMinp[N]; int Minv[N], Maxv[N];
// SumMaxMin SunMaxMinPos SumMax SumMin SumMaxPos SumMinpos MinVal MaxVal inline int Add(int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
} void Solve(int l, int r) {
if (l == r) { ans = Add(ans, 1ll * a[l] * a[r] % Mod); return ; }
int mid = (l + r) >> 1; Solve(l, mid); Solve(mid + 1, r); int p = mid, q = mid;
int minl = a[mid], maxl = a[mid]; SMM[mid] = SMMP[mid] = SMax[mid] = SMin[mid] = SMaxp[mid] = SMinp[mid] = 0;
For (i, mid + 1, r) {
if (i == mid + 1) {
Minv[i] = Maxv[i] = SMax[i] = SMin[i] = a[i];
SMinp[i] = SMaxp[i] = 1ll * a[i] * i % Mod;
SMM[i] = 1ll * a[i] * a[i] % Mod; SMMP[i] = 1ll * i * a[i] % Mod * a[i] % Mod;
continue ;
}
Minv[i] = min(a[i], Minv[i - 1]);
Maxv[i] = max(a[i], Maxv[i - 1]); SMin[i] = Add(SMin[i - 1], Minv[i]);
SMax[i] = Add(SMax[i - 1], Maxv[i]);
SMinp[i] = Add(SMinp[i - 1], 1ll * Minv[i] * i % Mod);
SMaxp[i] = Add(SMaxp[i - 1], 1ll * Maxv[i] * i % Mod);
SMM[i] = Add(SMM[i - 1], 1ll * Minv[i] * Maxv[i] % Mod);
SMMP[i] = Add(SMMP[i - 1], 1ll * i * Minv[i] % Mod * Maxv[i] % Mod);
} Fordown (i, mid, l) {
chkmin(minl, a[i]); chkmax(maxl, a[i]); while (p < r && Minv[p + 1] >= minl) ++ p;
while (q < r && Maxv[q + 1] <= maxl) ++ q; int gapl = min(p, q), gapr = max(p, q);
ans = Add(ans, 1ll * Sum(mid - i + 2, gapl - i + 1) * minl % Mod * maxl % Mod);
if (p < q) ans = Add(ans, (((SMinp[q] - SMinp[p]) - 1ll * (SMin[q] - SMin[p]) * (i - 1)) % Mod + Mod) * maxl % Mod);
if (p > q) ans = Add(ans, (((SMaxp[p] - SMaxp[q]) - 1ll * (SMax[p] - SMax[q]) * (i - 1)) % Mod + Mod) * minl % Mod);
ans = Add(ans, (((SMMP[r] - SMMP[gapr]) - 1ll * (SMM[r] - SMM[gapr]) * (i - 1)) % Mod + Mod) % Mod);
}
} int main () { File();
n = read(); For (i, 1, n) a[i] = read();
Solve(1, n);
printf ("%d\n", ans); return 0;
}

最新文章

  1. Android基础总结(九)
  2. 《InsideUE4》UObject(一)开篇
  3. jquery 序列化
  4. php大力力 [042节] 今天做了一个删除功能
  5. jsp编写页面时常见错误提示
  6. s2-032批量脚本
  7. winform属性
  8. PHP 读json文件并转php配置文件
  9. C++ XML 解释库
  10. IOS 开展 分别制定了iphone 和 ipad 好? 或开发一个 Universal好?
  11. C#调用Outlook来发送邮件
  12. LeanCloud 调研报告
  13. Memcached在Linux环境下的使用详解
  14. Percona XtraBackup 8.0, 安装与测试
  15. JQ JS复制到剪贴板
  16. PAT A1151 LCA in a Binary Tree (30 分)——二叉树,最小公共祖先(lca)
  17. odoo学习之弹框显示
  18. 让Windows加入域的PowerShell
  19. 下载google play下的app
  20. ubuntu 安装时分辨率太小 导致无法继续安装

热门文章

  1. 同一个解决方案或有依赖关系的两个项目引用同名但不同版本的DLL
  2. Android自动化测试之:获取 参数:comonentName 的值方法
  3. 《Head First 设计模式》例子的C++实现(2 观察者模式)
  4. ubuntu12.04安装mininet
  5. JDK1.7 HashMap 导致循环链表
  6. MySQL主主同步配置
  7. sublime text3 安装package control 出现问题解决过程记录
  8. Notes of Daily Scrum Meeting(12.24)
  9. checkbox未选中不提交数据
  10. Machine Learning Based Proactive Flow Entry Deletion for OpenFlow