基础算法笔记2

基础算法笔记2

前缀和

定义——前缀和可以简单理解为【数列的前n项和】,是一种重要的预处理方式,能大大降低查询的时间复杂度。

一维前缀和模板

S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

例题

有N 个的正整数放到数组 A里,现在要求一个新的数组B,新数组的第 i个数 B[i]是原数组 A第0到第i个数的和。

#include  <iostream>
using  namespace  std;
int  N,  A[10000],  B[10000];
int  main()  {  
cin  >>  N;  
for  (int  i  =  0;  i  <  N;  i++)  
{  cin  >>  A[i];  }  // 前缀和数组的第一项和原数组的第一项是相等的。  
B[0]  =  A[0];  
for  (int  i  =  1;  i  <  N;  i++)  
{  // 前缀和数组的第 i 项 = 原数组的 0 到 i-1 项的和 + 原数组的第 i 项。  B[i]  =  B[i  -  1]  +  A[i];  }  
for  (int  i  =  0;  i  <  N;  i++)  
{  cout  <<  B[i]  <<  " ";  }  
return  0;}

二维前缀和模板

S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

模板题

子矩阵的和

#include<iostream>
using namespace std;
#define N 1010

int a[N][N];
int s[N][N];

int main()
{
	int n, m, q;
	int i, j;
	cin >> n >> m >> q;
	for(i = 1; i <= n; i++)
	for(j = 1; j <= m; j++)
	{
		scanf("%d",&a[i][j]);
		s[i][j] = s[i - 1][j] + s[i][j - 1] + a[i][j] - s[i - 1][j - 1];
	}
	
	while(q--)
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >>y2;
		cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
	} 
	return 0; 
}

差分

定义——差分是一种和前缀和相对的策略,可以当做是求和的逆运算。

一维差分模板

给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

差分(模板题)

#include<iostream> 
using namespace std;
#define N 100010
int a[N];  //前缀和 
int b[N]; //差分 

void insert(int l, int r, int c)
{
	b[l] += c;
	b[r + 1] -= c;
}
int main()
{
	int n, m;
	int i;
	scanf("%d%d",&n, &m);
	for(i = 1; i <= n; i++)
	{
		scanf("%d",&a[i]);
		insert(i, i, a[i]);
	}
	while(m--)
	{
		int l, r, c;
		cin >> l >> r >> c;
		insert(l, r, c);
	}
	for(i = 1; i <= n; i++) 
	{
		b[i] +=b[i - 1];  //等价于 a[i] = a[i - 1] + b[i],输出 a[i] 就行 
		cout << b[i] << ' ';
	}
	cout << endl;	
	return 0;
 } 

二维差分模板

数组的首元素为0,不用它,因为 b[1][1] 需用到 b[0][0] .

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

差分矩阵(模板题)

#include <iostream>
using namespace std;
#define N 1010
int a[N][N]; //前缀和
int b[N][N]; //差分
void insert(int x1, int y1, int x2, int y2, int c)
{
	b[x1][y1] += c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y1] -= c;
	b[x2 + 1][y2 + 1] += c;
 } 
 
int main()
{
	int n, m, q;
	int i, j;
	scanf("%d%d%d",&n, &m, &q); 
	for(i = 1; i <= n; i++)
	for(j = 1; j <= m; j++)
	{
		scanf("%d",&a[i][j]);
		insert(i, j, i, j, a[i][j]); 
	}
	while(q--)
	{
		int x1, y1, x2, y2, c;
		cin >> 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];
		cout << b[i][j] << ' ';
	}
	cout << endl;
}
	return 0; 
}

刷题get的小知识:同余定理:数论中的重要概念。给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(mod m)。对模m同余是整数的一个等价关系。
出自洛谷P3131 [USACO16JAN] Subsequences Summing to Sevens S

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值