1 条题解
-
0
自动搬运
来自洛谷,原作者为

kkksc03
洛谷吉祥物 DA✩ZE搬运于
2025-08-24 21:45:56,当前版本为作者最后更新于2013-10-07 22:37:04,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目大意:将1~n*m分别放入n*m的格子矩阵里,其中的一些格子有特殊要求(周围的8个格子都要比它大),问方案数。
解决:从小到大放数,则一个普通格子只有等它周围的特殊格子都放完数了才能放数。在不考虑本题中“.”的格子不能是蓄水池的条件的情况下,我们可以写出如下记忆化搜索的方程式f[k][s]=sum{f[k-1][s’]}。其中sum为求和,k为放到了第几个数,s为蓄水池的放数状态(二进制状压),s’表示由s少放一个蓄水池能达到的状态。最后f[n*m][s全放]即为解。本题n<=4,m<=7,最多只有8个蓄水池,故此解可行。
本题的难点在于“.”的格子不能是蓄水池。我们可以用容斥原理来解决。我们设在原来的基础上又增加了p个蓄水池,若p为奇数,则ans应减去f[n*m][s全放],否则为加上。由于本题对于蓄水池的限制很足(不能相邻),所以这样的枚举次数不会太多,耗时也不大。
状态压缩记忆化搜索也可以写成搜索(即标程做法),所有测试点均在100ms内解决。
#include <iostream> using namespace std; const int maxp = 8; const int maxs = 1 << maxp; const int mod = 12345678; const int maxrow = 4; const int maxcol = 7; const int maxn = maxrow * maxcol + 2; int n, m, ans; int f[maxs][maxn], x[maxp], y[maxp], tp; bool use[maxrow][maxcol]; char graph[maxrow][maxcol]; void init() { scanf("%d%d\n", &n, &m); for (int i = 0; i < n; ++i) gets(graph[i]); } bool in_range(int x, int y) { return x >= 0 && y >= 0 && x < n && y < m; } int calc() { tp = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) if (graph[i][j] == 'X') x[tp] = i, y[tp++] = j; memset(f, 0, sizeof(f)); f[0][0] = 1; for (int s = 0; s < 1 << tp; ++s) { memset(use, 1, sizeof(use)); for (int i = 0; i < tp; ++i) if (!(s & (1 << i))) for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if (in_range(x[i] + dx, y[i] + dy)) use[x[i] + dx][y[i] + dy] = 0; int cnt = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) if (use[i][j]) ++cnt; for (int i = 0; i <= cnt; ++i) if (f[s][i]) { f[s][i + 1] = (f[s][i + 1] + f[s][i] * (cnt - i)) % mod; for (int j = 0; j < tp; ++j) if (!(s & (1 << j))) f[s | (1 << j)][i + 1] = (f[s | (1 << j)][i + 1] + f[s][i]) % mod; } } return f[(1 << tp) - 1][n * m]; } void search(int x, int y, int k) { if (x >= n) ans = (ans + k * calc()) % mod; else if (y >= m) search(x + 1, 0, k); else { search(x, y + 1, k); bool ok = 1; for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if (in_range(x + dx, y + dy) && graph[x + dx][y + dy] == 'X') ok = 0; if (ok) { graph[x][y] = 'X'; search(x, y + 1, -k); graph[x][y] = '.'; } } } int solve() { for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) if (graph[i][j] == 'X') for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if ((dx || dy) && in_range(i + dx, j + dy) && graph[i + dx][j + dy] == 'X') return 0; ans = 0; search(0, 0, 1); return (ans + mod) % mod; } int main() { freopen("mon.in", "r", stdin); freopen("mon.out", "w", stdout); init(); printf("%d\n", solve()); return 0; }[/cdec]
- 1
信息
- ID
- 2233
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者