惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
S
SegmentFault 最新的问题
V
Visual Studio Blog
J
Java Code Geeks
宝玉的分享
宝玉的分享
美团技术团队
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hackread – Cybersecurity News, Data Breaches, AI and More
有赞技术团队
有赞技术团队
量子位
Martin Fowler
Martin Fowler
MyScale Blog
MyScale Blog
Google DeepMind News
Google DeepMind News
Jina AI
Jina AI
博客园 - 叶小钗
月光博客
月光博客
P
Proofpoint News Feed
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
Stack Overflow Blog
Stack Overflow Blog

MoonLab

VSCode + OpenOCD 远程调试开发STM32 Clangd + VSCode使用方法 Keil5 编译错误 error: call to undeclared function '__enable_irq' BTSNOOP is FUN! 2025蓝桥杯赛后总结 三星ZFold 3改造 JavaScript 逆向 Steam 登录二维码 快速求解平方根倒数算法 Protobuf Android设备安装Debian成为BT下载服务器 [双系统] Windows 更新摧毁了我的Linux系统 Reading List Golang embed 使用问题 Hexo博客自动备份插件 云盘备份支持 通过汇编分析栈、函数调用 esp&ebp Git push 出现 permisson denied error 403 坑:Litepal save方法返回true却没有保存 Android Shizuku源码分析 第二篇 Android Shizuku源码分析 Android 监听第三方Activity的一举一动 Android笔记#1 View的事件分发机制解析 知乎日报的问题 使用Hexo Hello World Ubnutu 无法启动网易云音乐 - 总结 Windows 好软推荐 | 这一定是良心软件 typecho - http转https 如何评价Android P MoonLab MoonLab
算法 - 前缀和
LingC · 2025-05-04 · via MoonLab

在需要频繁地求数组中区间的和的情景下,前缀和数组十分有用。花费 $O(n)$ 的时间生成前缀和,之后只需要 $O(1)$ 的时间计算区间和。

定义一个数组a = [1, 2, 3, 4, 5],它的前缀和数组:

prefix[0] = 1
prefix[1] = 1 + 2 = 3
prefix[2] = 1 + 2 + 3 = 6
prefix[3] = 1 + 2 + 3 + 4 = 10
prefix[4] = 1 + 2 + 3 + 4 + 5 = 15

要计算 $[i,j]$ 区间的和,可以用 prefix[j] - prefix[i-1] 算出,其中 i = 0 下溢时直接取 prefix[j]

vector<int> prefix(n);
int sum = 0;
for(int i = 0; i < n; i++) {
	sum += i;
	prefix[i] = sum;
}

C++的numeric库提供了一个方便的函数partial_sum可以快速计算前缀和。

vector<int> arr[n], prefix(n);
for(int i=0;i<n;i++) cin >> arr[i];
partial_sum(arr.begin(), arr.end(), prefix.begin());

Practice: CF-1398C

Codeforce例题 C. Good Subarrays

对于一个数组,有多少子数组符合条件:子数组内所有元素相加等于子数组的长度。

  • 当遇到数字0,区间长度增加但区间的和不变,此时对区间的影响为-1
  • 当遇到数字1,区间长度加1,但需要额外一个元素来填充,此时对区间的影响为0
  • 当遇到数字x,此时对区间的影响为 x-1

我们所要寻找的subarray,则是区间的影响为0的。

比如 120 这三个数,如果每位减1,可以得到 0 1 -1

如果使用一维循环就能发现:

  • 0 符合,则$a_{1...1}$ 是好数组
  • 0 + 1 + -1 也符合,则$a_{1...3}$ 也是好数组。

但是如果要发现 $a_{2...3}$ (1 + -1) 也是好数组,则需要了解另一个trick。

这道题的本质是寻找出相加和等于 x 的子数组数量。

$prefix[i]-prefix[j]=x$

$prefix[j]=prefix[i]-x$

我们希望统计出截至对于任意的 i 的所有相加和为 x 的子数组数量。

对于每个 $prefix[i]$, 只需要统计之前有多少个 $prefix[j]$ 存在,实际上就是统计有多少个 $prefix[i]-x$ 存在。

因此我们总是先定义一个哈希表

将之前存在的 $prefix[j]$ 的数量加进答案

将当前的sum记录下来

#include <bits/stdc++.h>
using namespace std;
int main() {
	int t; cin >> t;
	while(t--) {
		string a;
		int n; cin >> n >> a;
		long long ans = 0, sum = 0;
		map<int, int> mp;
		for(int i=0;i<n;i++) {
			sum += a[i] - '0' - 1;
			if(sum==0) ans++;		
			ans += mp[sum];
			mp[sum]++;
		}
		cout << ans << endl;
	}
	return 0;
}

差分

差分可以看作是前缀和的逆运算。

a数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组

则满足,a[i] = b[1] + b[2]+ b[3] +,,,,,, + b[i]

b[1] = a[1] - a[0]

b[2] = a[2] - a[1]

b[n] = a[n] - a[n-1]

a数组中的[l, r]区间中的每一个数都加上c,只需对差分数组b做 b[l] + = cb[r+1] -= c。时间复杂度为O(1), 大大提高了效率。

Prefix XOR

pass

前缀积

pass

writing started at 2025-02-08 19:22, ended 2025-05-04


Refs

https://codeforces.com/blog/entry/140458

https://cses.fi/problemset/task/1661