题解 [AGC033D] Complexity
首先,我们不难想到一个暴力 dp:设
但此时我们注意到一个问题:答案是很小的,因为我们可以通过每次在两个维度之一上二分做到
考虑交换状态和答案,改设
初值:
转移分为如下三种情况。
- 矩形
(j, k, l) 复杂度\leq i - 1 时,其复杂度也一定\leq i ,则dp_{i, j, k, l} \leftarrow \max(dp_{i, j, k, l}, dp_{i - 1, j, k, l}) 。 - 横着切一刀,此时我们贪心地一定会尽量从满足复杂度
\leq i - 1 且最大的位置切开,则dp_{i, j, k, l} \leftarrow \max(dp_{i, j, k, l}, dp_{i - 1, dp_{i - 1, j, k, l} + 1, k, l}) 。 - 竖着切一刀,此时我们需要枚举切点,则
dp_{i, j, k, l} \leftarrow \max(dp_{i, j, k, l}, \displaystyle\max_{x = k}^{l - 1} \min(dp_{i - 1, j, k, x}, dp_{i - 1, j, x + 1, l})) 。
答案:
直接做的时间复杂度是
但是这道题在今天的模拟赛中的数据范围达到了
要是我们能不枚举竖着的切点就好了!打印出切点会发现:
知道这一条性质后对切点双指针即可。时间复杂度为
证明:首先我们知道
我们将
代码:
#include <stdio.h>
#include <math.h>
int sum[187][187], dp[7][187][187][187];
char s[187][187];
inline int get_sum(int l1, int r1, int l2, int r2){
return sum[r1][r2] - sum[r1][l2 - 1] - sum[l1 - 1][r2] + sum[l1 - 1][l2 - 1];
}
inline int max(int a, int b){
return a > b ? a : b;
}
inline int min(int a, int b){
return a < b ? a : b;
}
int main(){
int n, m, k;
scanf("%d %d", &n, &m);
k = ceil(log2(n)) + ceil(log2(m));
for (int i = 1; i <= n; i++){
scanf("%s", &s[i][1]);
for (int j = 1; j <= m; j++){
sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + (s[i][j] == '.' ? 1 : 0);
}
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
int pos = n;
for (int x = j; x <= m; x++){
while (pos >= i){
int y = get_sum(i, pos, j, x);
if (y == 0 || y == (pos - i + 1) * (x - j + 1)) break;
pos--;
}
if (pos < i) break;
dp[0][i][j][x] = pos;
}
}
}
if (dp[0][1][1][m] == n){
printf("0");
return 0;
}
for (int i = 1; i <= k; i++){
int cur = i & 1, pre = cur ^ 1;
for (int j = 1; j <= n; j++){
for (int x = 1; x <= m; x++){
int pos = x;
for (int y = x; y <= m; y++){
while (pos + 1 < y && min(dp[pre][j][x][pos], dp[pre][j][pos + 1][y]) <= min(dp[pre][j][x][pos + 1], dp[pre][j][pos + 2][y])) pos++;
dp[cur][j][x][y] = max(dp[pre][j][x][y], max(dp[pre][dp[pre][j][x][y] + 1][x][y], min(dp[pre][j][x][pos], dp[pre][j][pos + 1][y])));
}
}
}
if (dp[cur][1][1][m] == n){
printf("%d", i);
return 0;
}
}
return 0;
}