ブルーブリッジカップ デイリークエスチョン 2023.9.18

蘭橋杯 2022 第 13 回省大会 実際の質問 - 統計部分行列 - C 言語ネットワーク (dotcpp.com)

質問の説明

N × M 行列 A が与えられた場合、部分行列内のすべての数値の合計が指定された整数 K を超えないような部分行列 (最小 1 × 1、最大 N × M) がいくつあるか数えてください。 

分析する

範囲の問題などを考慮しない場合は、2 桁のプレフィックスの合計を使用して、それを段階的にリストすることができます。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n, m, k, ans, a[N][N], s[N][N];
int main()
{
	cin >> n >> m >> k;
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= m; j ++)
		{
			cin >> a[i][j];
		}
	}
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= m; j ++)
		{
			s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
		}
	}
	ans = 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 ++)
				{
					if (s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] <= k)ans ++;
				}
			}
		}
	}
	cout << ans;
	return 0;
}

ただし4重ループで制限時間を超えてしまう

したがって、最適化を検討することができます

上下の境界をループし、ダブルポインタを使用して左右の境界をリストします。範囲は <= k である必要があるため、これを超える場合はポインタを移動します。

up と down の列挙は 1 次元の問題とみなすことができます。各列は 1 次元配列と同等の要素とみなすことができます。この配列内でどの区間 <= k であるかを求めます

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n, m, k, sum, ans, a[N][N], s[N][N];
int main()
{
	cin >> n >> m >> k;
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= m; j ++)
		{
			cin >> a[i][j];
		}
	}
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= m; j ++)
		{
			s[i][j] = s[i - 1][j] + a[i][j];//算出这一列的前缀和 
		}
	}
	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 += s[j][r] - s[i - 1][r];
			 	while(sum > k)
			 	{
			 		sum -= s[j][l] - s[i - 1][l];
			 		l ++;
				}
				ans += r - l + 1;
			} 
		}
	}
	cout << ans;
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/m0_75087931/article/details/132992879
Recomendado
Clasificación