题意
给一个网格,每个格子是黑的或者白的。定义一个网格的复杂度是:
- 这个网格只有一种颜色,则复杂度是0
- 否则,复杂度是 .
求整个网格的复杂度
5s
题解
- 的dp是显然的
- 考虑到答案是 级别的,设 表示以 到 为左边界的复杂度 的网格最右端。
- 更新方法仍然是考虑横着切还是竖着切。
- 仍然要优化,竖着切的时候二分一下,
- 发现随着左边界长度的递增,竖着切的转移点是单调的。
下面是二分的
#include <bits/stdc++.h>
using namespace std;
const int N = 190;
int n, m;
char a[N][N];
int o;
int f[2][N][N][N];
int main() {
freopen("d.in", "r", stdin);
cin >> n >> m;
for(int i = 1; i <= n; i++) scanf("%s", a[i] + 1);
for(int j = m; j; j--) {
for(int i = 1; i <= n; i++) {
for(int k = i; k <= n; k++) if(a[k][j] == a[i][j]) {
f[o][j][i][k] = j;
if (a[i][j] == a[i][j + 1]) {
f[o][j][i][k] = max(j, f[o][j + 1][i][k]);
}
} else break;
}
}
for(int ans = 0; ans <= 20; ans++) {
if (f[o][1][1][n] == m) {
printf("%d\n", ans); return 0;
}
memset(f[1 - o], 0, sizeof f[1 - o]);
for(int j = 1; j <= m; j++) {
for(int i = 1; i <= n; i++) {
for(int z = i; z <= n; z++) {
int g = f[o][j][i][z];
if (f[o][j][i][z] > 0 && f[o][j][i][z] < m)
g = max(g, f[o][ f[o][j][i][z] + 1 ][i][z]);
if (i != z) {
int l = i, r = z - 1, ret = l;
while (l <= r) {
int mid = l + r >> 1;
if (f[o][j][i][mid] >= f[o][j][mid + 1][z]) {
ret = mid, l = mid + 1;
} else r = mid - 1;
}
g = max(g, min(f[o][j][i][ret], f[o][j][ret + 1][z]));
ret ++;
if (ret < z)
g = max(g, min(f[o][j][i][ret], f[o][j][ret + 1][z]));
}
f[1 - o][j][i][z] = g;
}
int e = j;
}
}
o = 1 - o;
}
}