AtCoder Grand Contest 033 D Complexity

发布时间 2023-07-05 15:02:08作者: zltzlt

洛谷传送门

AtCoder 传送门

这题感觉实在太 educational 了。

容易想到设 \(f_{u, d, l, r}\) 表示 \((u, l), (d, r)\) 这个矩形的复杂度。但是状态数就已经 \(O(n^2m^2)\) 了。

发现矩形复杂度 \(\le \left\lceil{\log n + \log m}\right\rceil\)考虑交换 dp 状态和答案,设 \(f_{i, u, l, r}\) 表示复杂度 \(\le i\) 的矩形,左上角是 \((u, l)\),右上角是 \((u, r)\) 的矩形,右下角 \((d, r)\)\(d\) 最大能是多少。

转移有分割行和分割列两种情况。注意到分割列时最优切点单调,于是可以双指针。复杂度 \(O(n m^2 (\log n + \log m))\)

code
// Problem: D - Complexity
// Contest: AtCoder - AtCoder Grand Contest 033
// URL: https://atcoder.jp/contests/agc033/tasks/agc033_d
// Memory Limit: 512 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 190;

int n, m, f[2][maxn][maxn][maxn], a[maxn][maxn];
char s[maxn][maxn];

inline int qsum(int xl, int xr, int yl, int yr) {
	return a[xl - 1][yl - 1] + a[xr][yr] - a[xl - 1][yr] - a[xr][yl - 1];
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%s", s[i] + 1);
		for (int j = 1; j <= m; ++j) {
			a[i][j] = a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1] + (s[i][j] == '#');
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			for (int k = j; k <= m; ++k) {
				int l = i, r = n, pos = i - 1;
				while (l <= r) {
					int mid = (l + r) >> 1;
					int t = qsum(i, mid, j, k);
					if (t == 0 || t == (mid - i + 1) * (k - j + 1)) {
						pos = mid;
						l = mid + 1;
					} else {
						r = mid - 1;
					}
				}
				f[0][i][j][k] = pos;
			}
		}
	}
	if (f[0][1][1][m] == n) {
		puts("0");
		return;
	}
	for (int d = 1, o = 1;; ++d, o ^= 1) {
		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= m; ++j) {
				for (int k = j, x = j; k <= m; ++k) {
					f[o][i][j][k] = max(f[o ^ 1][i][j][k], f[o ^ 1][f[o ^ 1][i][j][k] + 1][j][k]);
					while (x + 1 < k && min(f[o ^ 1][i][j][x], f[o ^ 1][i][x + 1][k]) <= min(f[o ^ 1][i][j][x + 1], f[o ^ 1][i][x + 2][k])) {
						++x;
					}
					if (j < k) {
						f[o][i][j][k] = max(f[o][i][j][k], min(f[o ^ 1][i][j][x], f[o ^ 1][i][x + 1][k]));
					}
				}
			}
		}
		if (f[o][1][1][m] == n) {
			printf("%d\n", d);
			return;
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}