前缀和 = =

 一维前缀和:

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

从S[1]开始,S[0]设为0

二维前缀和:

1、S[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];
		}
	}

2、子矩阵和

//S[i,j] = 第i行第j列格子左上部分所有元素的和

//求s[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];
	}
}

//以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和为:
S[x2,y2] - S[x1 - 1,y2] - S[x2,y1 - 1] + S[x1 - 1,y1 - 1]

题目1:(一维前缀和)

题目描述:

输入一个长度为 n的整数序列。接下来再输入 m个询问,每个询问输入一对 l,r。

对于每个询问,输出原序列中从第 l个数到第 r个数的和。

输入格式

第一行包含两个整数 n和 m。

第二行包含 n个整数,表示整数数列。

接下来 m行,每行包含两个整数 l 和 r,表示一个询问的区间范围。

输出格式

共 m行,每行输出一个询问的结果。

数据范围

1 ≤ l ≤ r ≤ n,1 ≤ n,m ≤ 100000,
−1000 ≤ 数列中元素的值 ≤ 1000

输入样例:

5 3

2 1 3 6 4

1 2

1 3

2 4

输出样例:

3

6

10

AC代码:

#include<bits/stdc++.h>
 

using namespace std;

const int N = 1e5 + 10;

int a[N],s[N];


int main()
{
	ios::sync_with_stdio(false); // 提高cin的读取速度 
	int i;
	int n,m;
	cin >> n >> m;
	for(i = 1; i <= n; i ++)  cin >> a[i];
	for(i = 1 ; i <= n ; i ++)  s[i] = s[i - 1] + a[i]; // 前缀和的初始化
	while(m --)
	{
		int l,r;
		int ans;
		cin >> l >> r;
		ans = s[r] - s[l - 1];
		cout << ans << endl;
	} 
    return 0;
}

题目2:(二维前缀和裸题)

题目描述:

输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式:

第一行包含三个整数 n,m,q。

接下来 n行,每行包含 m个整数,表示整数矩阵。

接下来 q行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。

输出格式:

共 q行,每行输出一个询问的结果。

数据范围:

1≤n,m≤1000,
1≤q≤200000,
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

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 1e3 + 10;

int a[N][N],s[N][N]; 
int n,m,q;

int main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(false);
	
	int i,j;
    
    cin >> n >> m >> q;
    
    for(i = 1 ; i <= n ; i ++)
    {
    	for(j = 1 ; j <= m ; j ++)
    	{
    		cin >> 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;
		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;
}

题目3:(二维前缀和)

题目描述
一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。
现在地图上有n(N ≤ 10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。
若目标位于爆破正方形的边上,该目标将不会被摧毁。

输入描述:
输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi 。

输出描述:
输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

AC代码:

#include <bits/stdc++.h>
 
using namespace std;
  
const int N = 5010; // N表示点最多的数量
int a[N][N];
 
int main()
{
    int i,j,x,y,v;
    int t,r;
    int ans = 0;
    cin >> t >> r;
    int xx = r, yy = r; // xx和yy表示边界,初始化为最小的r
     
    while(t --)
    {
        cin >> x >> y >> v;
        x ++;  y ++; // 坐标x,y都要加1,题目的坐标从0开始
        a[x][y] = v;
        xx = max(xx,x);
        yy = max(yy,y);
    }
    for(i = 1 ; i <= xx ; i ++)
    {
        for(j = 1 ; j <= yy ; j ++)
        {
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + a[i][j]; // 计算前缀和
        }
    }
    for(i = r ; i <= xx ; i ++)
    {
        for(j = r; j <= yy ; j ++)
        {
            ans = max(ans,a[i][j] - a[i - r][j] - a[i][j - r] + a[i - r][j - r]); // 用提前算好的前缀和减去其他部分再补上多剪的那部分
        }
    }
    cout << ans << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

21RGHLY

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

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

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

打赏作者

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

抵扣说明:

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

余额充值