前缀和数组

矩阵前缀和

前缀和与矩阵前缀和常用于竞赛中,处理矩阵求和问题。

一维前缀和

\[\begin{align} & 有一个一维数组x和它的前缀和数组y\\ & y[n]=\sum_{i=0}^{n}x[i] \end{align} \]

for(int i=0;i<n;i++)
{
    if(i==0) y[i]=x[i];
    else y[i]=y[i-1]+x[i];
}

二维前缀和

\[\begin{align} & 假设有二维数组a,对应的前缀和数组b\\ & b[i][j]的值是以元素a[i][j]为右下角的子矩阵的元素和\\ & 计算公式:b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j] \end{align} \]

在与矩阵处理有关的计算中,常常在原有的矩阵外加一圈元素(这样做可以使编程简单),即编程时要创建一个\((n+2)\times(m+2)\)的矩阵,在中间的部分放置原来的元素,其他的位置放置0.

计算前缀和矩阵:

for(int i=1;i<n+1;i++)
    for(int j=1;j<m+1;j++)
    {
        if(j==1&&i==1) b[i][j]=a[i][j];//第一个元素的值
        else if(j==1) b[i][j]=b[i-1][j]+a[i][j];//第一列
        else if(i==1) b[i][j]=b[i][j-1]+a[i][j];//第一行
        else b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j];
    }

\[\begin{align} & 假设要找的子矩阵的左上坐标为(x_1,y_1),右下角坐标为(x_2,y_2)\\ & 则该子矩阵的和为b[x_1,y_1]-b[x_1-1][y_2]-b[x_2][y_1-1]+b[x_1-1][y_1-1] \end{align} \]

例题:CSP_202104_2

#include <iostream>
#include <vector>

using namespace std;


int findmax(int x,int y) {
	return x > y ? x : y;
}

int findmin(int x,int y) {
	return x < y ? x : y;
}



int main(void) {
	//读输入
	int n, L, r, t;
	cin >> n >> L >> r >> t;
	//二维数组
	vector<vector<int>> matrix(n+2,vector<int>(n+2,0));
	for (int i = 1; i < n+1; i++)
		for (int j = 1; j < n+1; j++)
			cin>>matrix[i][j];


	//算前缀和矩阵
	vector<vector<int>> b(n+2, vector<int>(n+2, 0));
	for(int i=1;i<n+1;i++)
		for (int j = 1; j < n+1; j++) {
			if (i == 1 && j == 1)
				b[i][j] = matrix[i][j];
			else if (i == 1)
				b[i][j] = b[i][j - 1] + matrix[i][j];
			else if (j == 1)
				b[i][j] = b[i - 1][j] + matrix[i][j];
			else
				b[i][j] = b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] + matrix[i][j];
		}


	//统计
	int result = 0;
	for(int i=1;i<n+1;i++)
		for (int j = 1; j < n+1; j++) {
			//子矩阵左上角坐标
			int i1 = findmax(i-r,1);
			int j1 = findmax(j-r,1);
			
			//子矩阵右下角坐标
			int i2 = findmin(i + r, n);
			int j2 = findmin(j + r, n);

			//用前缀和矩阵计算子矩阵的和
			int sum = b[i2][j2] - b[i2][j1 - 1] - b[i1 - 1][j2] + b[i1 - 1][j1 - 1];

			//平均值
			int num = (i2 - i1 + 1) * (j2 - j1 + 1);
			double mean = (double)sum / (double)num;

			if(mean <= t)
				result++;
		}
	cout << result << endl;
}
posted @ 2022-03-04 00:56  带带绝缘体  阅读(70)  评论(0)    收藏  举报