码迷,mamicode.com
首页 > 其他好文 > 详细

[THOJ 1587] 小方格

时间:2017-09-07 18:09:38      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:for   int   最大的   gis   style   长度   错误   stdin   void   

题意

  给定 $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] 小方格

标签:for   int   最大的   gis   style   长度   错误   stdin   void   

原文地址:http://www.cnblogs.com/Sdchr/p/7490723.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!