前缀和数组
矩阵前缀和
前缀和与矩阵前缀和常用于竞赛中,处理矩阵求和问题。
一维前缀和
\[\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;
}

浙公网安备 33010602011771号