【二分+前缀和+后缀和】codeforces 2026 D. Sums of Segments
题目
https://codeforces.com/problemset/problem/2026/D
题意
第一行输入一个正整数 \(n(1 \leq n \leq 3e5)\),第二行输入 \(n\) 个整数 \(a_1, a_2, ..., a_i, ..., a_n(-10 \leq a_i \leq 10)\),第三行输入一个正整数 \(q(1 \leq q \leq 3e5)\),随后 \(q\) 行,每行输入两个整数 \(l_i, r_i(1 \leq l_i \leq r_i \leq \frac{n(n+1)}{2})\)。
对于数组 \(a\),我们会得到一个数组 \(b = [a_1, a_1 + a_2, ..., a_1 + a_2 + ... + a_n, a_2, a_2 + a_3, ..., a_2 + a_3 + ... + a_n, ..., a_n]\) 共 \(\frac{n(n + 1)}{2}\) 个元素,对于每个询问要求的是 \(\sum_{j = l_i}^{r_i}{b_j}\)。
题解
对于数组 \(a = [a_1, a_2, ..., a_i, ..., a_n]\),由于 \(1 \leq n \leq 3e5\),那么 \(b\) 元素个数会达到 \(1 \leq \frac{n(n+1)}{2} \leq 45000000000\) 的量级,因此不能直接求出 \(b\) 的每一个元素。不妨对数组 \(b\) 分为 \(n\) 组:
第一组
\(a_1, a_1 + a_2, ..., a1_ + a_2 + ... + a_n\)
第二组
\(a_2, a_2 + a_3, ..., a_2 + a_3 + ... + a_n\)
...
第 \(n\) 组
\(a_n\)
易知从第一组到第 \(n\) 组的元素个数分别是 \(n, n - 1, ..., 1\),若只是求出其中一组,时间复杂度为 \(O(n)\) 是可以接受的。
观察可以发现:第二组可以由第一组每个元素都删去一个 \(a_1\) 得到;第三组可以由第二组每个元素都删去一个 \(a_2\) 得到;以此类推。于是可以先计算出\(sum_1(a_1 + a_2 + ... + a_n)\),\(sum_2(a_2 + ... + a_n)\), ..., \(sum_n(a_n)\)。
假设我想计算 \(b\) 第 \(1 ~ x\) 项的和,那么需要计算出第 \(x\) 项位于第几个 \(sum\),计算方式可以使用二分法。不妨视为第 \(i\) 个,然后计算 \(sum_i\) 需要删掉的元素个数 \(cnt\)。此时问题就转化为如何计算出需要删掉的元素的和,或者是如何计算出最后一组不包括被删除元素的元素之和?
不妨假设 \(n = 4,x = 2\),那么此时 \(cnt = 2,sum_1 = a_1 + (a_1 + a_2) + (a_1 + a_2 + a_3) + (a_1 + a_2 + a_3 + a_4),\sum_{j=1}^{2}{b_j} = a_1 + (a_1 + a_2)\),可得 \(\sum_{j=1}^{2}{b_j} = sum_1 - (a_1 + a_2 + a_3) - (a_1 + a_2 + a_3 + a_4)\)。
删除的元素可以视为 \((a_1 + a_2 + a_3) + (a_1 + a_2 + a_3 + a_4) = 2 \times (a_1 + a_2) + a_3 + (a_3 + a_4) = cnt \times (a_1 + a_2) + a_3 + (a_3 + a_4)\)。观察分好组的数据,易知 \(a_3 + (a_3 + a_4)\) 刚好是倒数第 \(cnt\) 组。由归纳法,可以得出结论:
\(sum_i - sum_cnt - cnt \times 剩余的数最大值\) 就是最后一个 \(sum_i\) 剩余的值。至于前面的 \(sum_1~sum_i-1\) 直接使用前缀和维护即可。
参考代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
using namespace std;
using ll = long long;
constexpr int N = 3e5 + 7;
int n, q;
ll l, r;
ll a[N];
ll b[N];//第 i 组元素的总和
ll c[N];//维护第 1~i 组的总元素个数,分别是 n, n + (n - 1), n + (n - 1) + (n - 2), ...
ll apre[N];//a的前缀和
ll apst[N];//a的后缀和
ll bpre[N];//b的前缀和
ll calc(ll x) {//计算出从 b1~bx 的和
int loc = lower_bound(c + 1, c + 1 + n, x) - c;//计算出第 x 项所在组 loc
ll res = bpre[loc];
if (c[loc] > x) {
res = bpre[loc - 1];
int deleteNum = c[loc] - x;//需要删掉的数的数量
ll lastNum = apst[loc] - apst[n - deleteNum + 1];//删掉 deleteNum 个数后剩余最大元素
res += b[loc] - b[n - deleteNum + 1] - lastNum * deleteNum;//第 loc 组的和减去 倒数第 deleteNum 组的和并减去 deletNum 个剩余最大元素
}
return res;
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++ i) {
cin >> a[i];
apre[i] += apre[i - 1] + a[i];//求数组 a 的前缀和
}
for (int i = n; i >= 1; -- i) {
apst[i] = apst[i + 1] + a[i];//求数组 b 的前缀和
b[i] = apre[i] + b[i + 1];//数组 a 的前缀和的前缀和,也就是第 i 组的和
}
c[1] = n;//第一组的元素个数
for (int i = 2; i <= n; ++ i) {
c[i] = c[i - 1] + (n - i + 1);//第一组到第 i 组的总元素个数
b[i] = b[i - 1] - a[i - 1] * (n - i + 2);//第 i 组的元素之和
}
for (int i = 1; i <= n; ++ i) bpre[i] = b[i] + bpre[i - 1];//数组 b 前缀和的前缀和,也就是第一组到第 i 组的总元素之和
cin >> q;
while (q --) {
cin >> l >> r;
cout << calc(r) - calc(l - 1) << '\n';
}
return 0;
}
【二分+前缀和+后缀和】codeforces 2026 D. Sums of Segments的更多相关文章
- Codeforces Round #381 (Div. 2) D. Alyona and a tree 树上二分+前缀和思想
题目链接: http://codeforces.com/contest/740/problem/D D. Alyona and a tree time limit per test2 secondsm ...
- AcWing:139. 回文子串的最大长度(字符串Hash + 前缀和 + 后缀和 + 二分)
如果一个字符串正着读和倒着读是一样的,则称它是回文的. 给定一个长度为N的字符串S,求他的最长回文子串的长度是多少. 输入格式 输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个 ...
- 139. 回文子串的最大长度(回文树/二分,前缀,后缀和,Hash)
题目链接 : https://www.acwing.com/problem/content/141/ #include <bits/stdc++.h> using namespace st ...
- cf1043E. Mysterious Crime(二分 前缀和)
题意 题目链接 Sol 考场上做完前四题的时候大概还剩半个小时吧,那时候已经困的不行了. 看了看E发现好像很可做?? 又仔细看了几眼发现这不是sb题么... 先考虑两个人,假设贡献分别为\((x, y ...
- POJ 3061 (二分+前缀和or尺取法)
题目链接: http://poj.org/problem?id=3061 题目大意:找到最短的序列长度,使得序列元素和大于S. 解题思路: 两种思路. 一种是二分+前缀和.复杂度O(nlogn).有点 ...
- 递归算法(二)——前缀转后缀
源码:pretopost.cpp #include "stdafx.h" #include <stdio.h> #include <stack> /**** ...
- POJ 2752 Seek the Name, Seek the Fame (KMP的next函数,求前缀和后缀的匹配长度)
给一个字符串S,求出所有前缀,使得这个前缀也正好是S的后缀.升序输出所有情况前缀的长度.KMP中的next[i]的意义就是:前面长度为i的子串的前缀和后缀的最大匹配长度.明白了next[i],那么这道 ...
- 【Todo】字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树
另开一文分析字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树. 先来一个汇总, 算法: 本文中提到的字符串匹配算法有:KMP, BM, Horspool, Sunday, BF, ...
- 关于字符串 “*****AB**C*D*****” 中前缀、后缀和中间 '*' 的处理
一.删除前缀 '*' #include<iostream> #include<cstdio> using namespace std; //主函数 int main() { ] ...
- Poj 3061 Subsequence(二分+前缀和)
Subsequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12333 Accepted: 5178 Descript ...
随机推荐
- 微信小程序上拉加载
下面是一个示例,在个人使用的过程中按自己需求进行更改 创建一个DataController控制器 php artisan make:controller DataController 创建一个Data ...
- 技术分享 | 徐轶韬:从MySQL5.7升级到MySQL 8.0
在6月20日举办的[墨天轮数据库沙龙-MySQL 5.7 停服影响与应对方案]中,甲骨文MySQL解决方案首席工程师徐轶韬分享了<从MySQL5.7升级到MySQL 8.0>主题演讲,本文 ...
- 2021年9月国产数据库排行榜-墨天轮:达梦奋起直追紧逼OceanBase,openGauss反超PolarDB再升一位
2021年9月国产数据库排行榜已在墨天轮发布,本月参与排名的数据库总数达到了142个. 一.9月国产数据库流行度排行榜前15名 先来看看排行榜前五名,虽然PingCAP的TiDB分数本月下降31.82 ...
- 2022年2月国产数据库排行榜:冠军宝座面临挑战,OceanBase 重返 TOP3
大家好!文章开始本是用"新春快乐!虎年吉祥!"和大家打个招呼,无奈时间过得太快而文章整理得很慢,眼看崭新的三月还有几天就到来,那就在这里祝屏幕前的你在三月比二月更优秀! 月初,20 ...
- Access to XMLHttpRequest at xxxx from origin xxx has been blocked by CORS policy: No 'Access-Control- Allow-Origin' header is present on the requested resource
错误:控制台报错 : network 自动发起了请求: 解决办法: 找到 \node_modules\sockjs-client\dist\sockjs.js 文件 然后 crtl + g 快捷键跳 ...
- SQL注入利用及绕过总结
SQL注入及绕过姿势总结 概述 SQL注入指用户输入的参数可控且没有被过滤,攻击者输入的恶意代码被传到后端与SQL语句一起构造并在数据库中执行 不同数据库的语法可能存在差异,以MySQL为例,其他差异 ...
- 题解:AT_abc370_c [ABC370C] Word Ladder
题目传送门 luogu观看 简要题意 给两个序列 \(S\) 和 \(T\),输出的第一个数是它能改变的总个数,后面跟着的第 \(i\) 个是改变 \(i\) 个数之后,字典序最小的结果. 思路 当 ...
- Windows电脑无法给airpods充电的解决办法
耳机盒与电脑都有TYPEC接口,由于驱动问题,接在一起是充不了电的,需要更改设置解决: 打开设置 -> 蓝牙与其他设备 -> 显示更多设备 往下翻,找到"更多设备与打印机设置&q ...
- NIO聊天室
SocketChannel 和 ServerSocketChannel ServerSocketChannel 用于创建服务器端套接字,而 SocketChannel 用于创建客户端套接字.它们都支持 ...
- MYSQL 批量删除以特定前缀开头的表
前言 这是工作中确实会用到,比如分库分表后有t_order_01.t_order_02.t_order_03...t_order_08 这样的表. 测试过程中造了大量数据进行测试,其中可能含有部分脏数 ...