AT4927 [AGC033D] Complexity
https://www.luogu.com.cn/problem/AT4927
O ( n 5 ) O ( n 4 l o g n ) O(n^5)O(n^4logn) O(n5)O(n4logn)的DP显然过不了
考虑优化,修改状态,容易发现最多只会切log刀,所以我们可以把答案记在状态里
d p [ o ] [ i ] [ j ] [ k ] dp[o][i][j][k] dp[o][i][j][k]表示已经切了 o o o刀,从第 i i i行,第 j j j行,从第 k k k列开始最多能往右拓展多少
然后转移考虑竖着切就是
d
p
[
o
]
[
i
]
[
j
]
[
k
]
=
d
p
[
o
−
1
]
[
i
]
[
j
]
[
d
p
[
o
−
1
]
[
i
]
[
j
]
[
k
]
+
1
]
dp[o][i][j][k]=dp[o-1][i][j][ \ \ dp[o-1][i][j][k] + 1\ \ ]
dp[o][i][j][k]=dp[o−1][i][j][ dp[o−1][i][j][k]+1 ]
横着切就是上下的取
m
i
n
min
min,显然分成上下部分尽量接近的时候是最优的,二分即可
具体实现可以看代码
code:
#include<bits/stdc++.h>
#define N 195
using namespace std;
int s[N][N], f[2][N][N][N], n, m;
int check(int x, int y, int xx, int yy) {
int sz = (xx - x + 1) * (yy - y + 1);
int gs = s[xx][yy] - s[x - 1][yy] - s[xx][y - 1] + s[x - 1][y - 1];
return sz == gs || !gs;
}
int find(int o, int i, int j, int k) {
int l = i - 1, r = j, ret = 0;
while(l + 1 < r) {
int mid = (l + r) >> 1;
int x = f[o][i][mid][k];
int y = f[o][mid + 1][j][k];
ret = max(ret, min(x, y));
if(x > y) l = mid;
else r = mid;
}
return ret;
}
void dp(int o) {
for(int i = 1; i <= n; i ++) {
for(int j = i; j <= n; j ++) {
for(int k = 1; k <= m; k ++) {
int l = f[o ^ 1][i][j][k], s = 0;
if(l != m) {
s = f[o ^ 1][i][j][l + 1];
s = max(s, find(o ^ 1, i, j, k));
} else s = m;
f[o][i][j][k] = s;
//printf(" %d %d %d %d %d\n", o, i, j, k, s);
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) {
char c;
scanf(" %c", &c);
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + (c == '#');
}
// for(int i = 1; i <= n; i ++) {
// for(int j = 1; j <= m; j ++) printf("%d ", s[i][j]); printf("\n");
// }
for(int i = 1; i <= n; i ++) {
for(int j = i; j <= n; j ++) {
for(int k = 1; k <= m; k ++) {
int l = k - 1, r = m + 1;
while(l + 1 < r) {
int mid = (l + r) >> 1;
if(check(i, k, j, mid)) l = mid;
else r = mid;
}
f[0][i][j][k] = l;
// printf("%d %d %d %d \n", i, j, k, l);
}
}
}
int ans = 0;
while(f[ans & 1][1][n][1] < m) ans ++, dp(ans & 1);
printf("%d", ans);
return 0;
}