[THOJ 1587] 小方格
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[THOJ 1587] 小方格相关的知识,希望对你有一定的参考价值。
题意
给定 $n \times n$ 的网格图, 有坏点.
将没有坏的点进行黑白染色, 对于每一种染色方案, 我们都能看得到一个最大的边长为 $i$ 的纯白色正方形.
求最大的纯白色正方形的边长为 $0, 1, ..., n$ 的方案数.
$n \le 8$ .
分析
我们考虑求出最大的纯白色正方形的边长小于 $1, 2, ..., n, n+1$ 的方案数 $ans_1, ans_2, ..., ans_{n+1}$ , 然后进行差分即可求得答案.
枚举 $x$ , 考虑如何求 $ans_x$ .
我们考虑进行状态压缩 DP , $f[i][S]$ 表示当前 DP 到第 $i$ 行, 状态为 $S$ 的方案数.
状态 $S$ 包含了 $n - x + 1$ 个整数 $S_1, S_2, ..., S_{n - x + 1}$ , $S_j$ 表示 $(i,j), (i, j+1), ..., (i, j+x-1)$ 共同隆起的长度, 那么要求 $0 \le S_j < x$ .
至于转移, 我们枚举 $s$ , 然后 $2 ^ n$ 枚举下一行的情况 $Next$ , 然后将 $s$ 在 $Next$ 的作用下转化成 $t$ , $f[i+1][t] += f[i][s]$ .
考虑如何转移: t = Transfer(x, S, Next) .
对于 Next 中不选择的位置 j , $[j - x + 1, j]$ 在 $S$ 中的对应位都为 0 .
对于其他位置, 要保证它至少可以再拓展一位, 直接加 1 .
如果加上 1 达到了 x , 那么当前状态就要舍去.
注意如果我们算的是 小于等于 x 的方案数 , 那么 "对于其他位置, 直接加 1 ." 就是错误的了.
例如:
1 0
o *
↓
1 0
而实际上我们会忽略掉这种情况.
分析: 实际上 1 不能继续拓展, 应该就是 1 .
但是我们强制拓展了, 强制拓展就被忽略掉了.
其实我们也可以在 x = t + 2 的时候算 <= t 的 .
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 6 #define P(i, a, b) for (register int i = (a); i >= (b); i--) 7 8 const int N = 10; 9 const int MOD = (int)1e9 + 7; 10 11 int n; char s[N][N]; 12 int Pow[N], f[N][5000]; 13 int ans[N]; 14 15 // Next 0 : o 1 : * 16 inline bool Legal(int row, int Next) { 17 F(i, 1, n) 18 if (s[row][i] == ‘*‘ && !(Next >> i-1 & 1)) 19 return false; 20 return true; 21 } 22 inline int Trans(int sz, int s, int Next) { 23 static int Del[N]; memset(Del, 0, sizeof Del); 24 F(i, 1, n) 25 if (Next >> i-1 & 1) { 26 Del[i]++; 27 if (i - sz > 0) Del[i - sz]--; 28 } 29 P(i, n-1, 1) Del[i] += Del[i+1]; 30 F(i, 1, n-sz+1) { 31 int key = s / Pow[i-1] % sz; 32 if (Del[i] > 0) s -= key * Pow[i-1]; 33 else { 34 if (key == sz-1) return -1; 35 s += Pow[i-1]; 36 } 37 } 38 return s; 39 } 40 41 int main(void) { 42 #ifndef ONLINE_JUDGE 43 freopen("sqr.in", "r", stdin); 44 #endif 45 46 scanf("%d", &n); F(i, 1, n) scanf("%s", s[i]+1); 47 48 F(sz, 1, n+1) { 49 memset(Pow, 0, sizeof Pow); 50 Pow[0] = 1; 51 F(i, 1, n-sz+1) Pow[i] = Pow[i-1] * sz; 52 53 memset(f, 0, sizeof f), f[0][0] = 1; 54 F(i, 0, n-1) 55 F(s, 0, Pow[n-sz+1] - 1) if (f[i][s] != 0) { 56 F(Next, 0, (1 << n) - 1) if (Legal(i+1, Next)) { 57 int t = Trans(sz, s, Next); 58 if (~t) f[i+1][t] = (f[i+1][t] + f[i][s]) % MOD; 59 } 60 } 61 62 // < sz <-> <= sz-1 63 F(s, 0, Pow[n-sz+1] - 1) 64 ans[sz-1] = (ans[sz-1] + f[n][s]) % MOD; 65 } 66 67 P(i, n, 1) ans[i] = (ans[i] - ans[i-1]) % MOD; 68 F(i, 0, n) printf("%d\n", (ans[i] + MOD) % MOD); 69 70 return 0; 71 }
以上是关于[THOJ 1587] 小方格的主要内容,如果未能解决你的问题,请参考以下文章