算法学习(三)前缀和差分

前缀和:Sn 类似于积分
在这里插入图片描述

差分:dn 类似于微分

1、一维前缀和

#include<iostream>
using namespace std;
/*
	对于每个询问,输出原序列中从第l个数到第r个数的和
	第一行包含2个整数:n和m
	第二行包含n个整数,表示整块数列
	接下来m行,每行都包含2个整数l和r,表示一个询问区间范围
	1<= l <= r <= n
	1<=n,m<=100000
	-1000<= 数列中元素的值 <= 1000 
*/
const int N = 100010;
int n, m,l,r;
int a[N], s[N] = { 0 };

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		scanf_s("%d", &a[i]);		// 前缀和初始化

	for (int i = 1; i <= n; i++) 
		s[i] = s[i - 1] + a[i];		// 区间和计算

	while (m--) {
		scanf_s("%d %d", &l, &r);
		cout << s[r] - s[l - 1] << endl;
	}
}
/*
	5  3 
	2 1 3 6 4
	1 2
	1 3
	2 4
	答案:
	3   
	6
	10
*/

#include<iostream>
using namespace std;
const int N = 100010;
int n, m,l,r;
int a[N], s[N] = { 0 };

int main() {
	std::ios::sync_with_stdio(false);		
	/*	取消cin于stdin的同步,与scanf效率相差无几;不可以与scanf混用,但是还是没有scanf的速度快
		要不就全部scanf,printf,
		要不就ios::sync_with_stdio(false)+全部cin,cout,
		不要混用避免不必要的WA.
	*/
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++) 
		s[i] = s[i - 1] + a[i];
	while (m--) {
		cin >> l >> r;
		cout << s[r] - s[l - 1] << endl;
	}
}
/*
	5  3 
	2 1 3 6 4
	1 2
	1 3
	2 4
	答案:
	3
	6
	10
*/

2、二维前缀和

在这里插入图片描述

#include<iostream>
using namespace std;
/*
*	范围:
	1<=n,m<=1000
	1<=q<=10000
	1<=x1<=x2<=n
	1<=y1<=y2<=m
	-1000<=元素的值<=1000
	输入样例:
	3   4  3
	1  7 2 4
	3  6 2 8
	2  1 2 3
	1  1 2 2
	2  1 3 4
	1  3 3 4
	输出样例:
	17
	27
	21
*/
const int N = 1010;
int n, m, q,i,j;
int a[N][N], s[N][N];
int main() {
	scanf_s("%d%d%d", &n, &m, &q);
	for ( i = 1; i <= n; i++)
		for ( j = 1; j <= m; j++)
			scanf_s("%d", &a[i][j]);

	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
			s[i][j] = s[i - 1][j ] + s[i][j - 1] - s[i - 1][j - 1]+a[i][j];

	while (q--) {
		int x1, y1, x2, y2;
		scanf_s("%d%d%d%d", &x1, &y1, &x2,&y2);
		printf("%d\n", s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
	}
}

3、一维差分

在这里插入图片描述

#include<iostream>
using namespace std;
/*
	输入:长度为n的整数序列
	再输入 :m个操作,每个操作包含3个整数l,r,c:表示将序列中[l,r]直接的每个数都加上c.
	第一行:n,m
	第二行n个整数
	m行,每行:l,r,c
	输出格式:1行,n个整数,表示最终序列。
	1<=n,m<=10000;
	1<=l<=r<=n,
	-1000<=c<=1000
	-1000<=整数序列中元素的值<=1000
	输入样本:
	6 3
	1 2 2 1 2 1
	1 3 1
	3 5 1
	1 6 1
	输出样例:
	3 4 5 3 4 2
*/
const int N = 100010;
int a[N], b[N];
int n, m,i,l,r,c;
// 核心算法
void insert(int l, int r, int c) {
	b[l] += c;
	b[r+1] -= c;
}
int main(){
	scanf_s("%d%d", &n, &m);

	for (i = 1; i <= n; i++)
		scanf_s("%d", &a[i]);

	for (i = 1; i <= n; i++)
		insert(i, i, a[i]);	// 得到原来b序列

	while (m--) {
		scanf_s("%d%d%d", &l, &r, &c);
		insert(l, r, c);
	}

	for (i = 1; i <= n; i++)
		b[i] += b[i - 1];
	for (i = 1; i <= n; i++)
		printf("%d ", b[i]);
}

4、二维差分

在这里插入图片描述

#include<iostream>
using namespace std;
/*
	输入:一个n*m的整数矩阵 再输入q个操作包括五个整数x1,y1,x2,y2,c;
	其中(x1,y1)和(x2,y2)表示一个子矩阵的左上角坐标和右下角坐标
	每个操作要把选中的子矩阵中的每个元素的值都加上c
	输入格式:
	第一行: n,m,q
	n行:每行包含m个整数,表示整数矩阵
	输出格式:
	共n行,每行m个整数,表示所有操作进行完毕后的最终矩阵。
	数据范围:
	1<=n,m<=1000
	1<=q<=100000
	1<=x1<=x2<=n
	1<=y1<=y2<=m
	输入样例:
		3 4 3
		1 2 2 1
		3 2 2 1
		1 1 1 1 
		1 1 2 2 1
		1 3 2 3 2
		3 1 3 4 1
	输出样例:
	2  3  4  1
 	4  3  4  1
	2  2  2  2
*/
const int N = 1010;
int a[N][N], b[N][N];
int n, m, q,i,j;

// 核心算法
void insert(int x1, int y1, int x2, int y2, int c) {
	b[x1][y1] += c;
	b[x2 + 1][y1] -= c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y2 + 1] += c;
}

int main() {
	scanf_s("%d%d%d", &n, &m, &q);

	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
			scanf_s("%d", &a[i][j]);

	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
			insert(i, j, i, j, a[i][j]);

	int x1, y1, x2, y2,c;
	while (q--) {
		scanf_s("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
		insert(x1, y1, x2, y2, c);
	}
	
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] ;

	for (i = 1; i <= n; i++) {
		for (j = 1; j <= m; j++) {
			printf("%2d ", b[i][j]);
		}
		printf("\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

广大菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值