关于前缀和

发布时间 2023-05-24 18:35:41作者: Gery_8002

Part1.1 一维前缀和

题目描述

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

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

输入格式

第一行包含两个整数 \(n\)\(m\)

第二行包含 \(n\) 个整数,表示整数序列

接下来 \(m\) 行,每行包含 \(2\) 个整数 \(l\)\(r\),表示一个询问的区间范围

输出格式

\(m\) 行,每行输出一个询问的结果

数据范围

\(1\) \(\leq\) \(l\) \(\leq\) \(r\) \(\leq\) \(n\)

\(1\) \(\leq\) \(n\) , \(m\) \(\leq\) \(100000\)

\(1000\) \(\leq\) 数列中元素的值 \(\leq\) \(1000\)

思路

定义 \(a\) 数组表示整数序列

\(b\) 数组表示 \(a\) 数组的前缀和

于是就有

int a[6] = {0,1,2,3,4,5};
int b[6] = {0,1,3,6,10,15};

可以发现

前缀和就是从位置 \(1\) 到位置 \(i\) 这个区间内的所有的数字之和

b[i] = a[1] + a[2] + ...+a[i]

又有

b[l] = a[1] + a[2] + ... + a[l];
b[r] = a[1] + a[2] + ... + a[l] + a[l+1] + a[l+2] + ... + a[r];

\[[l, r] = b[r] - b[l-1]; \]

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, a[N], b[N];
int main()
{
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++)
  {
    scanf("%d", &a[i]);
    b[i] = b[i - 1] + a[i];
  } 
  for (int i = 1; i <= m; i++)
  {
    scanf("%d%d", &l, &r);
    printf("%d", b[r] - b[l - 1]);
  }
  return 0;
}

Part1.2 习题

Luogu P2697 宝石串
Solution

Luogu P8218 求区间和
Solution

Part2.1 二维前缀和

题目描述

输入一个 \(n\)\(m\) 列的整数序列,再输入 \(k\) 个询问,每个询问包括 \(4\) 个整数 \(x_1\) , \(y_1\) , \(x_2\) , \(y_2\) ,表示一个子矩阵的左上角和右下角坐标

输入格式

第一行包含 \(3\) 个整数 \(n\) , \(m\) , \(k\)

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

接下来 \(k\) 行,每行包含 \(4\) 个整数 \(x_1\) , \(y_1\) , \(x_2\) , \(y_2\) ,表示一组询问

输出格式

\(k\) 行,每行输出 \(1\) 个询问的结果

数据范围

\(1\) \(\leq\) \(n\) , \(m\) \(\leq\) \(1000\)

\(1\) \(\leq\) \(k\) \(\leq\) \(200000\)

\(1\) \(\leq\) \(x_1\) \(\leq\) \(x_2\) \(\leq\) \(n\)

\(1\) \(\leq\) \(y_1\) \(\leq\) \(y_2\) \(\leq\) \(m\)

\(1000\) \(\leq\) 矩阵内元素的值 \(\leq\) \(1000\)

思路

二维前缀和是基于一维前缀和的,我们要求一个矩阵内一个任意的子矩阵的数的和

定义 \(s[i][j]\) 数组表示从 \((1, 1\)) 到 \((i, j)\) 构成矩阵内数的和

\(map[i][j]\) 即矩阵元素

公式

\[s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + map[i][j] \]

Code

#include<bits/stdc++.h>
using namespace std;
const int N =  1e4 + 10; 
int n, m, k;
int x1, y1, x2, y2;  
int map[N][N], s[N][N];
int main()  
{
	scanf("%d%d%d", &n, &m, &k);
  	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= m; j++)
  	scanf("%d", &map[i][j]), s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + map[i][j];
  	for (int i = 1; i <= k; i++)
	{
		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
		int l = s[x2][y2] + s[x1-1][y1-1] - s[x1-1][y2] - s[x2][y1-1];
		printf("%d\n", l);
	}
	return 0;                          
                          

Part2.2 习题

Luogu P1719 最大加权矩形

Luogu P1387 最大正方形

Luogu P2004 领地选择

Luogu P2280 [HNOI2003]激光炸弹

Luogu P3397 地毯
Solution

Luogu P7741 [AHOI2007] 石块地板

参考

OI-WiKi