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;
}

浙公网安备 33010602011771号