淺談二維前綴和


【二維前綴和】

【一維前綴和】

一維前綴和顧名思義
就是一維的前綴和
前綴和是什么呢?
前綴和就是到目前為止全部的和是多少
一維就是單純的一串數
他的前綴和就成了一維前綴和

【舉例】

\(1\ 2 \ 3 \ 4 \ 5 \ 6\)
他的前綴和依次就是 \(1 \ 3 \ 6 \ 10 \ 15 \ 21\)
\(i\)位置上的前綴和就是從第一個數到第\(i\)個數全部數的和

這樣就很顯然的知道了什么是一維前綴和了吧?

【二維前綴和是什么】

二維前綴和顧名思義
就是二維的前綴和
二維很顯然了
有x軸和y軸也就是一個面
這很顯然

那二維前綴和中一個f[i][j]表示的意思就是
以(1,1)為左上角以(i,j)為右下角這個矩陣里面數的和
如圖

f[i][j]表示的就是圖中紅色的部分

【二維前綴和怎么求】

這里先不說,先假設自己知道了每\(f[i][j]\)二維前綴和是多少
(這個鍋我背,因為一開始設計的問題,導致先解釋的求矩陣值而沒有解釋求\(f[i][j]\)的值,因這兩個很相似所以說一個就過了,先說了求矩陣那這里再說求點就有點重復了我嫌麻煩,所二維前綴和點的值就在最后說一下吧,在已知求矩陣的情況下)

【二維前綴和求矩陣元素和】

二維前綴和可以用來干什么呢?
一維前綴和你可以用來O(1)求某個點的值
那么類比一下
二維前綴和也是可以用來求某個矩陣的值的

但是怎么來求呢?

就如圖中
知道了兩個點的位置和他們的二維前綴和
圖中紅色是左上角的那個點的二維前綴和
紅色+黃色部分是右下角的那個點的二維前綴和
是不是可以用這個來求出他們之間的矩陣的和呢?
也就是這一部分:

圖中黑色的部分就是我們要求的那個矩陣和
看到這里yy一下
是不是可以通過某些奇怪的方法求出黑色部分是多少?

D點表示的二維前綴和值是紅色部分+兩個黃色部分+黑色部分
A點表示的是紅色部分
B點表示的是上面的黃色部分+紅色部分
C點表示的是下面的黃色部分+紅色部分

這樣是不是發現有什么神奇的東西快要出現了
這里面只有D的前綴和里面包括黑色部分
只要減去D里面的哪兩個黃色部分和紅色部分是不是就剩下了我們要求的黑色部分了?
那怎么減去呢?
可以這樣:
D - B - C + A
這就是二維前綴和最重要的部分了
化成二維數組的形式就是這樣的

\[f[i][j] - f[i - 1][j] - f[i][j - 1] + f[i - 1][j - 1] \]

【為什么上文成立】

繼續看上面那張圖
由D-B-C+A到方程式這個很顯然所以就不多說了
只要證明出D-B-C+A是正確的那就沒有問題了
這個可以化成:
紅色部分+上面的黃色部分+下面的黃色部分+黑色部分-上面的黃色部分-紅色部分-下面的黃色部分-紅色部分+紅色部分
這樣是不是很巧妙的就只剩下了黑色部分
所以成立

【補充 —— 二維前綴和怎么求】

這個可以類比上面求矩陣的思想
只是這個矩陣的右下角是(i,j),左上角也是(i,j)
就是一個11的矩陣
所以也是很好求的
但是上面是已知D,A,B,C求黑色部分
這里你只知道A,B,C和黑色部分
因為是一個1
1的矩陣嗎
所以黑色部分就只有一個元素也就是(i,j)坐標上的那個元素值
所以就可以個加法變減法,減法變加法一個性質的
通過A,B,C和黑色部分來求出D

D點表示的二維前綴和值是紅色部分+兩個黃色部分+黑色部分
A點表示的是紅色部分
B點表示的是上面的黃色部分+紅色部分
C點表示的是下面的黃色部分+紅色部分

所以D就可以等於B+C-D+黑色部分:
上面的黃色部分+紅色部分+下面的黃色部分+紅色部分-紅色部分+黑色部分
=上面的黃色部分+紅色部分+下面的黃色部分+黑色部分
剛好等於D
方程式為

\[f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + a[i][j] \]

【模板】

給個小板子
查詢某個矩陣里面數的總和

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int Max = 1003;
int a[Max][Max];
int f[Max][Max];
signed main()
{
	freopen("acioi.in","r",stdin);
	int n,m,c;
	cin >> n >> m >> c;
	for(register int i = 1;i <= n;++ i)
		for(register int j = 1;j <= m;++ j)
			cin >> a[i][j],f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + a[i][j];
	int k;
	cin >> k;
	for(register int i = 1;i <= k;++ i)
	{
		int x1,x2,y1,y2;//x1,y1是左上角的坐標,另一對是右下角的坐標 
		cin >> x1 >> y1 >> x2 >> y2;
		cout << f[x2][y2] - f[x1 - 1][y2] - f[x2][y1 - 1] + f[x1 - 1][y1 - 1]; 
	}
	cout << M << endl; 
	return 0;
}

【注意】

上面有許多坐標減去1的情況
是因為左上角的那個點表示的前綴和包括左上角的值
但是左上角這個點也包括在我們要求的矩陣內
所以不應該減去
這就是-1的原因了
其他不一樣的類比一下就好了哈

【例題】

【洛谷P2004領地選擇】

題面
題解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM