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;
}
posted @ 2019-10-29 23:06  wuhan2005  阅读(51)  评论(1编辑  收藏