BZOJ 3745: [Coci2015]Norma(分治)
题意
给定一个正整数序列 \(a_1, a_2, \cdots, a_n\) ,求
\]
\(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\) 分三种情况讨论。
对于 \(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
\]这部分用高斯求和优化即可。
对于 \(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)\) 就行了。那么每次计算就是前缀和相减,然后乘上系数就行了。
对于最后一部分 \(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;
}
BZOJ 3745: [Coci2015]Norma(分治)的更多相关文章
- bzoj 3745 [Coci2015]Norma——序列分治
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3745 如果分治,就能在本层仅算过 mid 的区间了. 可以从中间到左边地遍历左边,给右边两个 ...
- bzoj 3745: [Coci2015]Norma【分治】
参考:https://blog.csdn.net/lych_cys/article/details/51203960 真的不擅长这种-- 分治,对于一个(l,r),先递归求出(l,mid),(mid+ ...
- bzoj 3745: [Coci2015]Norma
Description Solution 考虑分治: 我们要统计跨越 \(mid\) 的区间的贡献 分最大值和最小值所在位置进行讨论: 设左边枚举到了 \(i\),左边 \([i,mid]\) 的最大 ...
- 【刷题】BZOJ 3745 [Coci2015]Norma
Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. Sample Input 4 2 4 1 4 Sam ...
- bzoj3745: [Coci2015]Norma 分治,单调队列
链接 bzoj 思路 首先\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=i}^{j}max(a_k)\)可以用单调队列求解.参见 ...
- [BZOJ3745][COCI2015]Norma[分治]
题意 题目链接 分析 考虑分治,记当前分治区间为 \(l,r\) . 枚举左端点,然后发现右端点无非三种情况: 极大极小值都在左边; 有一个在左边; 极大极小值都在右边; 考虑递推 \(l\) 的同时 ...
- 【BZOJ3745】[Coci2015]Norma cdq分治
[BZOJ3745][Coci2015]Norma Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. ...
- [BZOJ 3456]城市规划(cdq分治+FFT)
[BZOJ 3456]城市规划(cdq分治+FFT) 题面 求有标号n个点无向连通图数目. 分析 设\(f(i)\)表示\(i\)个点组成的无向连通图数量,\(g(i)\)表示\(i\)个点的图的数量 ...
- [BZOJ 2989]数列(CDQ 分治+曼哈顿距离与切比雪夫距离的转化)
[BZOJ 2989]数列(CDQ 分治) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]| ...
随机推荐
- phpstorm 2018.1.2的安装和破解
1.什么是phpstorm? PhpStorm是一个轻量级且便捷的PHP IDE,其旨在提高用户效率,可深刻理解用户的编码,提供智能代码补全,快速导航以及即时错误检查.但是phpstorm是商业软件, ...
- NOIP2018题解
Preface 联赛结束后趁着自己还没有一下子把题目忘光,所以趁机改一下题目. 没有和游记一起写主要是怕篇幅太长不美观. 因此这里我们直接讲题目,关于NOIP2018的一些心得和有趣的事详见:NOIP ...
- 机器学习sklearn19.0聚类算法——Kmeans算法
一.关于聚类及相似度.距离的知识点 二.k-means算法思想与流程 三.sklearn中对于kmeans算法的参数 四.代码示例以及应用的知识点简介 (1)make_blobs:聚类数据生成器 sk ...
- 校内模拟赛 虫洞(by NiroBC)
题意: n个点m条边的有向图,每一天每条边存在的概率都是p,在最优策略下,询问从1到n的期望天数. 分析: dijkstra. 每次一定会优先选dp最小的后继走,如果这条边不存在,选次小的,以此类推. ...
- Linux中2>&1使用
转:2>&1使用 一 相关知识 1)默认地,标准的输入为键盘,但是也可以来自文件或管道(pipe |).2)默认地,标准的输出为终端(terminal),但是也可以重定向到文件,管道或后 ...
- 如何在命令长度受限的情况下成功get到webshell(函数参数受限突破、mysql的骚操作)
0x01 问题提出 还记得上篇文章记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门),我们讲到了一些PHP的一些如何巧妙地绕过数字和字母受限的技巧,今天我要给大家分享的是如 ...
- Mysql之binlog日志说明及利用binlog日志恢复数据操作记录
众所周知,binlog日志对于mysql数据库来说是十分重要的.在数据丢失的紧急情况下,我们往往会想到用binlog日志功能进行数据恢复(定时全备份+binlog日志恢复增量数据部分),化险为夷! 一 ...
- JS中的跨域问题
一.什么是跨域? 1.定义:跨域是指从一个域名的网页去请求另一个域名的资源.比如从www.baidu.com 页面去请求 www.google.com 的资源.但是一般情况下不能这么做,它是由浏览器的 ...
- STL next_permutation()
用法 字典序全排列 可以发现函数next_permutation()是按照字典序产生排列的,并且是从数组中当前的字典序开始依次增大直至到最大字典序. 代码 #include<iostream&g ...
- pair work结对编程(张艺 杨伊)
一.结对编程人员: 张艺(学号后三位:185) 杨伊(学号后三位:151) 二.这是我们工作的样子:(图片) 三.结对编程优缺点: 优点: 1.结对编程时间紧密,在一定程度上可以督促双方学习,提高 ...