NOI模拟(10.29)T2 棋盘

来源:互联网 发布:淘宝卖aj的正品店 编辑:程序博客网 时间:2024/05/21 06:28

棋盘

题目背景:

10.29 NOI模拟T2

分析:状压DP

 

第一眼就知道是状压DP,第一反应就知道大致方法,然而,我写不出来啊woc······绝望·······

讲题,定义ans[size]表示魔法值大于等于size的方案数共有多少种,那么显然魔法值为size的方案数为ans[size] - ans[size + 1],现在我们来考虑怎么获得ans[size],我们先枚举当前的size,然后开始进行dp,定义dp[i][j]表示,完成前i行的染色,最后一行的状态为j的方案数,这里的j是一个size进制数,j的第k位表示k ~ k + size - 1当中,向上全部都被染过色的最小的层数,即,以k ~ k + size - 1为底,最大的被完全染色的矩形的高是多少,然后我们可以枚举新的一行的状态,先判断,i ~ i + size - 1的染色程度,然后枚举上一行的j进行转移,如果i ~ i + size - 1均被染色,那么转移位置的j的第i位应该比上一行的加1,否则直接清0,如果发现之前j的第i位已经为size - 1了,并且这一次也全部被染色,则表示不能转移,否则会形成魔法值为size的方案。然后ans[size]就等于总的染色方案数减去所有dp[n][i]之和,(dp[n][i]表示第n行状态为i的满足魔法值小于size的方案数,枚举i即可),至此就搞定啦,注意边界和清空即可。复杂度····我也不想算。

Source:

/*created by scarlyw*/#include <cstdio>#include <string>#include <algorithm>#include <cstring>#include <iostream>#include <cmath>#include <cctype>#include <vector>#include <set>#include <queue>#include <ctime>const int MAXN = 10;const int MAXX = 1000000;const int mod = 1000000000 + 7;int m, n;int ans[MAXN], ban[MAXN], p[MAXN];int dp[MAXN][MAXX];bool able[MAXN];char map[MAXN][MAXN];inline void add(int &x, int t) {x += t, (x >= mod) ? (x -= mod) : 0;}int main() {scanf("%d", &n), m = 1;for (int i = 1; i <= n; ++i) scanf("%s", map[i]);for (int i = 1; i <= n; ++i)for (int j = 0; j < n; ++j)if (map[i][j] == 'o') add(m, m);else ban[i] |= (1 << j);ans[0] = 1, ans[1] = m - 1, (ans[1] < 0) ? (ans[1] += mod) : 0;for (int size = 2; size <= n; ++size) {int end = n - size + 1;p[0] = 1, dp[0][0] = 1;for (int i = 1; i <= end; ++i) p[i] = p[i - 1] * size;for (int i = 1; i < p[end]; ++i) dp[0][i] = 0;for (int i = 1; i <= n; ++i) {for (int j = 0; j < p[end]; ++j) dp[i][j] = 0;for (int cur = 0, s = (1 << n); cur < s; ++cur) {if (cur & ban[i]) continue ;for (int j = 0; j < end; ++j) able[j] = true;for (int j = 0; j < n; ++j) {if (cur & (1 << j)) continue ;for (int l = 0; l < end; ++l) {if (j >= l && j < l + size)able[l] = false;}}for (int last = 0; last < p[end]; ++last) {if (dp[i - 1][last] == 0) continue ;int pos = last, suc = 0;for (int j = 0; j < end; ++j) {int t = pos / p[j] % size;if (!able[j]) t = 0;else if (t != size - 1) ++t;else {suc = -1;break ;}suc += t * p[j];}if (suc == -1) continue ;add(dp[i][suc], dp[i - 1][last]);}}}ans[size] = 0;for (int i = 0; i < p[end]; ++i) add(ans[size], dp[n][i]);ans[size] = m - ans[size], (ans[size] < 0) ? (ans[size] += mod) : 0;ans[size - 1] = ans[size - 1] - ans[size];(ans[size - 1] < 0) ? (ans[size - 1] += mod) : 0;}for (int i = 0; i <= n; ++i) std::cout << ans[i] << '\n';return 0;}

原创粉丝点击