CF293B Distinct Paths
首先这个题有一个坑点(?):当\(n+m-1>k\)时无解.显然嘛
所以\(n,m\leq1000\)?假的.
于是我们就可以愉快(?)的搜索了.
但是\(k^{n*m}\)依旧非常大,于是我们开始剪枝.
- 可行性剪枝:如果剩下的颜色不足以支持剩下的路程,就直接\(return\).
- 我们可以对于同一类数字(即输入数据中没有出现过的颜色)的答案直接算一个后乘这类数字的个数.
还有对于之前的颜色存储,可以使用状态压缩.
我是不会告诉你这样不卡常是过不了的
#pragma GCC optimize("Ofast,inline", 3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
const int mod = 1e9 + 7;
template<class TT>
il TT read() {
TT o = 0,fl = 1; char ch = getchar();
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') fl = -1, ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl * o;
}
int status[15][15], mp[15][15], cnt[15], num[2010], n, m, k;
int dfs(int x, int y) {
if (y == m + 1) ++x, y = 1;
if (x == n + 1) return 1;
status[x][y] = status[x - 1][y] | status[x][y - 1];
int res = 0, lst = -1;
if (n + m - x - y + 1 > k - num[status[x][y]]) return 0;
if (mp[x][y] != -1) {
if ((1 << mp[x][y]) & status[x][y]) return 0;
status[x][y] |= 1 << mp[x][y]; ++cnt[mp[x][y]];
res = dfs(x, y + 1);
status[x][y] ^= 1 << mp[x][y]; --cnt[mp[x][y]];
return res;
}
for (int i = 0; i < k; ++i)
if (!((1 << i) & status[x][y])) {
status[x][y] |= 1 << i; ++cnt[i];
if (cnt[i] == 1) {
if (lst == -1) lst = dfs(x, y + 1);
res += lst;
}
else res += dfs(x, y + 1);
res > mod ? res -= mod : 0;
status[x][y] ^= 1 << i; --cnt[i];
}
return res;
}
int main() {
for (int i = 1; i <= 2000; ++i) num[i] = num[i >> 1] + (i & 1);
n = gi(), m = gi(), k = gi();
if (n + m - 1 > k) return puts("0") & 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
mp[i][j] = gi() - 1, ++cnt[mp[i][j]];
printf("%d\n", dfs(1, 1));
return 0;
}