CF2159B思路分享(adhoc)

https://codeforces.com/problemset/problem/2159/B

题意概述

给定一个 \(n \times m\)\(01\) 矩阵,定义合法矩形为四个端点两两不重且值都为 \(1\) 的矩形。

对矩阵的每个格子,计算包含该格子的合法矩形的面积最小值,如果不存在,输出 \(0\)

思路

考虑固定左上角和左下角。

可以发现,此时完全覆盖另一合法矩形的合法矩形没有意义,因此考虑的所有合法矩形除了边界外一定不交。这样枚举是 \(\mathcal{O}(n^2 m)\) 的,可以启发式地选择较小的作为 \(n\),转置矩阵处理,这样最坏是 \(\mathcal{O}(nm \sqrt{nm})\)

考虑如何更新。

可以发现,当固定左上角时,较大的左下角的状态是可以覆盖较小的左下角的状态的,因此横坐标可以取后缀 \(min\) 维护;而纵坐标由于矩形不交,暴力更新即可。

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll INF = 9e18;

void solve(){
	int n,m;
	cin >> n >> m;

	vector<string> a(n+1);
	for (int i=1;i<=n;i++){
		cin >> a[i];
		a[i] = ' '+a[i];
	}

	bool f = false;

	if (n>m){
		vector<string> b(m+1,string(n+1,' '));

		for (int i=1;i<=n;i++){
			for (int j=1;j<=m;j++){
				b[j][i] = a[i][j];
			}
		}

		a = b;
		swap(n,m);
		f = true;
	}

	vector<vector<ll>> res(n+1,vector<ll>(m+1,INF));

	for (int u=1;u<=n;u++){
		vector<vector<ll>> temp(n+2,vector<ll>(m+1,INF));

		for (int d=u+1;d<=n;d++){
			int pre = 1;

			while (pre<=m && (a[u][pre]!='1' || a[d][pre]!='1')){
				pre++;
			}

			for (int j=pre+1;j<=m;j++){
				if (a[u][j]!='1' || a[d][j]!='1') continue;

				for (int x=pre;x<=j;x++){
					temp[d][x] = min(temp[d][x],(d-u+1ll)*(j-pre+1ll));
				}

				pre = j;
			}
		}

		for (int d=n;d>=u;d--){
			for (int j=1;j<=m;j++){
				temp[d][j] = min(temp[d][j],temp[d+1][j]);
				res[d][j] = min(res[d][j],temp[d][j]);
			}
		}
	}

	if (f){
		vector<vector<ll>> nres(m+1,vector<ll>(n+1));

		for (int i=1;i<=n;i++){
			for (int j=1;j<=m;j++){
				nres[j][i] = res[i][j];
			}
		}

		res = nres;
		swap(n,m);
	}

	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			if (res[i][j]==INF){
				cout << 0 << ' ';
			}
			else{
				cout << res[i][j] << ' ';
			}
		}
		cout << '\n';
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t;
	cin >> t;
	while (t--) solve();

	return 0;
}
posted @ 2026-05-09 19:35  kzssCCC  阅读(10)  评论(0)    收藏  举报