二维前缀和

二维前缀和:

求和的公式:s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]

s数组是前缀和数组,a数组保存(i,j)点的值,并且s数组保存的是从(1,1)到(i,j)的矩阵的和

 贴个代码:

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			long long x;
			cin >> x;
			mp[i][j] = mp[i - 1][j] + mp[i][j - 1] - mp[i - 1][j - 1] + x;
		}
	}

前缀和保存的是从(1,1)点开始计算的前缀和,如果想要从其他点开始计算前缀和的话,可以利用差分的操作。

贴个公式:ans=mp[x2][y2]-mp[x2][y1-1]-mp[x1-1][y2]+mp[x1-1][y1-1];

(x1,y1)是起点位置 (x2,y2)是终点位置

P8783 [蓝桥杯 2022 省 B] 统计子矩阵

贴个暴力前缀和的做法(80分)O(n^4)

#include <iostream>

using namespace std;

int n, m, k;
long long mp[510][510];

int main()
{
	cin >> n >> m >> k;

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			long long x;
			cin >> x;
			mp[i][j] = mp[i - 1][j] + mp[i][j - 1] - mp[i - 1][j - 1] + x;
		}
	}

	int cnt = 0;
	for (int x1 = 1; x1 <= n; x1++)
	{
		for (int y1 = 1; y1 <= m; y1++)
		{
			for (int x2 = x1; x2 <= n; x2++)
			{
				for (int y2 = y1; y2 <= m; y2++)
				{
					long long ans=mp[x2][y2]-mp[x2][y1-1]-mp[x1-1][y2]+mp[x1-1][y1-1];
					if (ans <= k)
						cnt++;
				}
			}
		}
	}
	cout << cnt << endl;

	return 0;
}

剩下的两个点会超时......

随便贴个正解(双指针)O(n^3)

#include <iostream>


using namespace std;


const int N=510;

int a[N][N];

int main ()
{
	int n,m,k;
	
	cin >> n>> m>>k;
	
	for (int i=1;i<=n;i++)
		for (int j = 1; j <= m ; j++)
			cin >> a[i][j],a[i][j] += a[i-1][j];
			
	long long res = 0; 
	for (int i=1;i<=n;i++)
	{
		for (int j=i;j<=n;j++)
		{
			for (int l = 1 , r = 1 , sum = 0 ; r <= m ; r++ )		
			{
				sum += a[j][r]-a[i-1][r];
				while (sum > k)
				{
					sum -= a[j][l]-a[i-1][l];
					l++;
				}
				res += r-l+1;
			}
				
		}
	}
	cout << res<< endl;
	
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值