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

BZOJ #2669 \ CQOI 2012 局部最小值

时间:2016-08-17 00:05:05      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:

题目描述:

在一个N * M的矩阵中填入1 ~ N * M的数,并限制一些位置为周围9个格中最小的,而其它位置不能满足这个条件。

解题思路:

考虑dp,F[i][s]表示填了前i个数,限制位置的填数状态为s,cnt[s]表示限制位置的状态为s时,可以填数的位置+限制位置已填数的数量。

那么 F[i][s] = F[i - 1][s] * (cnt[s] - i + 1) + ∑p∈s F[i - 1][s - p]。

但这样会忽略一些非限制的点满足了限制条件的情况。那我们就dfs把一些非限制点当作限制点,用上面dp做,再容斥掉。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 const int mo = 12345678, fx[8][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
  7 int T, n, m, tot, cnt[1 << 8], f[30][1 << 8], S, mar[10][10], ans;
  8 char s[10][10];
  9 
 10 void init() {
 11     tot = 0;
 12     for (int i = 1; i <= n; i ++)
 13         for (int j = 1; j <= m; j ++) if (s[i][j] == X) {
 14             tot ++;
 15             mar[i][j] = tot;
 16         } else mar[i][j] = 0;
 17     S = (1 << tot) - 1;
 18     for (int s = 0; s <= S; s ++) {
 19         int t = 0;
 20         for (int i = 1; i <= n; i ++)
 21             for (int j = 1; j <= m; j ++) {
 22                 if (mar[i][j] && ((1 << mar[i][j] - 1) & s)) t ++;
 23                 if (!mar[i][j]) {
 24                     int p = 0;
 25                     for (int k = 0; k < 8; k ++) {
 26                         int ni = i + fx[k][0], nj = j + fx[k][1];
 27                         if (ni < 1 || ni > n || nj < 1 || nj > m) continue;
 28                         if (mar[ni][nj] && (!((1 << mar[ni][nj] - 1) & s))) {
 29                             p = 1;
 30                             break;
 31                         } 
 32                     }
 33                     if (!p) t ++;
 34                 }
 35             }
 36         cnt[s] = t;    
 37     }
 38 }
 39 
 40 int dp() {
 41     for (int i = 1; i <= n * m; i ++)
 42         for (int s = 0; s <= S; s ++) {
 43             (f[i][s] = f[i - 1][s] * (cnt[s] - i + 1)) %= mo;
 44             for (int p = 1; p <= tot; p ++) if ((1 << p - 1) & s) {
 45                 (f[i][s] += f[i - 1][s ^ (1 << p - 1)]) %= mo;
 46             }
 47         }
 48     return f[n * m][S];
 49 }
 50 
 51 void dfs(int x, int y, int sum) {
 52     if (y == m + 1) {
 53         dfs(x + 1, 1, sum);
 54         return;
 55     }
 56     if (x == n + 1) {
 57         init();
 58         (ans += dp() * (sum & 1 ? -1 : 1) + mo) %= mo;
 59         return;
 60     } 
 61     dfs(x, y + 1, sum);
 62     int p = 0;
 63     for (int k = 0; k < 8; k ++) {
 64         int nx = x + fx[k][0], ny = y + fx[k][1];
 65         if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
 66         if (s[nx][ny] == X) {
 67             p = 1;
 68             break;
 69         }
 70     }
 71     if (s[x][y] == X) return;
 72     if (!p) {
 73         s[x][y] = X;
 74         dfs(x, y + 1, sum + 1);
 75         s[x][y] = .;
 76     }
 77 }
 78 
 79 int cheak() {
 80     for (int i = 1; i <= n; i ++)
 81         for (int j = 1; j <= m; j ++) if (s[i][j] == X) 
 82             for (int k = 0; k < 8; k ++) {
 83                 int ni = i + fx[k][0], nj = j + fx[k][1];
 84                 if (ni < 1 || ni > n || nj < 1 || nj > m) continue;
 85                 if (s[ni][nj] == X) return 0;
 86             }
 87     return 1;
 88 }
 89 
 90 int main() {
 91     scanf("%d", &T);
 92     f[0][0] = 1;
 93     while (T --) {
 94         ans = 0;
 95         scanf("%d %d", &n, &m);
 96         for (int i = 1; i <= n; i ++) scanf("%s", s[i] + 1);
 97         if (!cheak()) {
 98             printf("0\n");
 99             continue;
100         }
101         dfs(1, 1, 0);
102         printf("%d\n", ans);
103     }
104     return 0;
105 }

 

BZOJ #2669 \ CQOI 2012 局部最小值

标签:

原文地址:http://www.cnblogs.com/awner/p/5778215.html

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