[COCI2021-2022#6] Zemljište

maniubi發表於2024-09-10

[COCI2021-2022#6] Zemljište

題意

給出一個矩陣,一個子矩陣的權值為 \(|m-a|+|m-b|\)\(m\) 為子矩陣數值和,\(a,b\) 為給出的數。

求該矩陣權值最小的子矩陣。

思路

列舉子矩陣上界和下界,左右界使用雙指標列舉,令 \(a<b\)

對於每個左界,不斷擴充套件右界直到子矩陣和大於 \(b\),因為再往右擴充套件一定不優。

每次擴充套件時統計答案即可。

程式碼

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 505 + 5;
int r, s, a, b, ans = 1e9;
int v[N][N], sum[N][N];
int val(int x_1, int y_1, int x_2, int y_2) {
	return sum[x_2][y_2] - sum[x_1 - 1][y_2] - sum[x_2][y_1 - 1] + sum[x_1 - 1][y_1 - 1];
}
int calc(int x_1, int y_1, int x_2, int y_2) {
	return abs(a - val(x_1, y_1, x_2, y_2)) + abs(b - val(x_1, y_1, x_2, y_2));
}
void solve() {
	cin >> r >> s >> a >> b;
	if (a > b) swap(a, b);
	for (int i = 1; i <= r; i ++)
		for (int j = 1; j <= s; j ++)
			cin >> v[i][j];
	for (int i = 1; i <= r; i ++)
		for (int j = 1; j <= s; j ++)
			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] + v[i][j] - sum[i - 1][j - 1];
	for (int i = 1; i <= r; i ++) {
		for (int j = i; j <= r; j ++) {
			for (int L = 1, R = 1; L <= s; L ++) {
				R = max(L, R);
				while (R < s && val(i, L, j, R) <= b) 
					ans = min(ans, calc(i, L, j, R)), R ++;
				ans = min(ans, calc(i, L, j, R));
			}
		}
	}
	cout << ans << "\n";
} 
signed main() {
	int T = 1;
//	cin >> T;
	while (T --)
		solve();
	return 0;
}