题目

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的更多相关文章

  1. 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 ...

  2. AcWing:139. 回文子串的最大长度(字符串Hash + 前缀和 + 后缀和 + 二分)

    如果一个字符串正着读和倒着读是一样的,则称它是回文的. 给定一个长度为N的字符串S,求他的最长回文子串的长度是多少. 输入格式 输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个 ...

  3. 139. 回文子串的最大长度(回文树/二分,前缀,后缀和,Hash)

    题目链接 : https://www.acwing.com/problem/content/141/ #include <bits/stdc++.h> using namespace st ...

  4. cf1043E. Mysterious Crime(二分 前缀和)

    题意 题目链接 Sol 考场上做完前四题的时候大概还剩半个小时吧,那时候已经困的不行了. 看了看E发现好像很可做?? 又仔细看了几眼发现这不是sb题么... 先考虑两个人,假设贡献分别为\((x, y ...

  5. POJ 3061 (二分+前缀和or尺取法)

    题目链接: http://poj.org/problem?id=3061 题目大意:找到最短的序列长度,使得序列元素和大于S. 解题思路: 两种思路. 一种是二分+前缀和.复杂度O(nlogn).有点 ...

  6. 递归算法(二)——前缀转后缀

    源码:pretopost.cpp #include "stdafx.h" #include <stdio.h> #include <stack> /**** ...

  7. POJ 2752 Seek the Name, Seek the Fame (KMP的next函数,求前缀和后缀的匹配长度)

    给一个字符串S,求出所有前缀,使得这个前缀也正好是S的后缀.升序输出所有情况前缀的长度.KMP中的next[i]的意义就是:前面长度为i的子串的前缀和后缀的最大匹配长度.明白了next[i],那么这道 ...

  8. 【Todo】字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树

    另开一文分析字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树. 先来一个汇总, 算法: 本文中提到的字符串匹配算法有:KMP, BM, Horspool, Sunday, BF, ...

  9. 关于字符串 “*****AB**C*D*****” 中前缀、后缀和中间 '*' 的处理

    一.删除前缀 '*' #include<iostream> #include<cstdio> using namespace std; //主函数 int main() { ] ...

  10. Poj 3061 Subsequence(二分+前缀和)

    Subsequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12333 Accepted: 5178 Descript ...

随机推荐

  1. Dos常用命令 - Dir

    Dos命令,用于扫描当前目录创建目录清单 dir /s /b /ad >> "目录清单.txt" 解释: 将 dir /s /b /ad 生成的目录 追加写入目录清单. ...

  2. YashanDB发布会圆满收官,V23.1三大新品引领国产数据库技术与应用突破!

    11月8日,YashanDB 2023年度产品发布会在线上成功召开.本次产品发布会以"惟实·励新"为主题,宣布崖山数据库系统YashanDB 内核能力.产品形态.生态创新全面升级, ...

  3. vue3中的vue-18n的table表格标题不动态变化中英文

    使用 computed 即可 eg: const columns = computed(() => { return reactive<any>([ { title: proxy.$ ...

  4. 0608-nn和autograd的区别

    0608-nn和autograd的区别 目录 一.nn 和 autograd 的区别 二.Function 和 Module 在实际中使用的情况 pytorch完整教程目录:https://www.c ...

  5. 【技术分析】恶意 SPL 代币识别指南

    背景 在 EVM 生态上,存在各式各样的 ERC20 代币,因其实现方式有着极高的自由度,也催生了花样繁多的恶意代币.这些恶意代币通常会在代码中实现一些恶意的逻辑(禁止用户卖出,特权铸造或销毁等),其 ...

  6. CSP模拟10--总结

    今天是我第一次给模拟赛写正规总结--因为今天的题真的受不了了 四道数学题,一点都不拖泥带水的纯血数学题! T1.黑暗型高松灯 shit 本来是一道放在T4防AK的题,结果学长为了 恶心 锻炼一下我们, ...

  7. vue-cli 跳转到页面指定位置

    原文关注公众号,后台里留言可进行提问,可在后台留言向作者提问解答问题! https://mp.weixin.qq.com/s?__biz=Mzg3NTAzMzAxNA==&mid=224748 ...

  8. 万星开源项目:System Design Primer - 学习系统设计的必备指南

    GitHub 链接:https://github.com/donnemartin/system-design-primer 什么是 System Design Primer? System Desig ...

  9. Python3开启简易服务器

    nohup python3 -m http.server 3000 2>&1 &

  10. xtrabackup进行mysql数据库备份、还原

    xtrabackup简介 前面介绍mysqldump备份方式是采用逻辑备份,其最大的缺陷就是备份和恢复速度都慢,对于一个小于50G的数据库而言,这个速度还是能接受的,但如果数据库非常大,那再使用mys ...