一维/二维前缀和
一维/二维 前缀和
一维前缀和干什么用?
一维前缀和,用于数组中求
可是,我们的前缀和怎么做到捏?我们可以推一下捏:
我们先定义一个数组
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e7 + 5; // 成习惯了,真戒不掉QAQ
int n, m, a[MAXN];
ll sum[MAXN]; // 前缀记录数组
signed main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sum[0] = 0; // 全局变量,其实不写也行
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i]; // 用递推的思想, 因为a[1]~a[i](sum[i])的和一定是a[1]~a[i - 1]的和(sum[i - 1]) + a[i]
while (m--) { // 看个人写法吧
int x;
scanf("%d", &x);
printf("%lld\n", sum[x]);
}
return 0;
}
维前缀和还有一个作用,就是可以求区间和。怎么求捏?
我们可以发现,从
那么,就非常简单了,我们可以先求一遍前缀和,然后每一次询问就输出
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e7 + 5; // 成习惯了,真戒不掉QAQ
int n, m, a[MAXN];
ll sum[MAXN]; // 前缀记录数组
inline ll calc(int l, int r) {
return sum[r] - sum[l - 1];
}
signed main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sum[0] = 0; // 全局变量,其实不写也行
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i]; // 用递推的思想, 因为a[1]~a[i](sum[i])的和一定是a[1]~a[i - 1]的和(sum[i - 1]) + a[i]
scanf("%d", &m);
while (m--) {
int l, r;
scanf("%d %d", &l, &r);
printf("%lld\n", calc(l, r));
}
return 0;
}
其实,前缀和还有个很好用的东东:
差分!!!
假设,有这样一道题:
给一个数列
要求支持
问最后整个数列会变成什么样。
数据范围 : 对于所有的数据,保证
(你是不是在想:这是干嘛,跟前缀和有关系?)
答案是:肯定的!!!!
我们这么想,我们先设定一个差分数组
#include <bits/stdc++.h>
using namespace std;
int n, m;
int a[100010];
int c[100010];
long long int s[100010];
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= m; i++) {
int l, r;
scanf("%d %d", &l, &r);
c[l] += 1, c[r + 1] -= 1; // 在前端点 + 1, 没有了就 - 1
}
long long sum = 0;
for (int j = 1; j <= n; j++) {
sum += c[j];
s[j] = sum; // 做一次前缀和求差
}
for (int i = 1; i <= n; i++) {
s[i] += a[i]; // 加上差
printf("%lld ", s[i]);
}
return 0;
}
二维前缀和呢?
我们想要求出这样的和:
其实,求出这个,只需要用红色区和
核心就是:
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
sum[i][j] = a[i][j] + sum[i][j-1] + sum[i-1][j] -sum[i-1][j-1];
核心代码已给出,其余代码与一维前缀和类似,因时间需要(估计也没人爱看一大串又臭又长的非核心代码),便不再赘述。