CF1006F
题意
问你矩阵所有从左上角到右下角的路径中异或和等于 \(k\) 的路径数量。
分析
常规思路就是从左上角开始搜索,但是由于 \(n,m\le20\) 所以时间复杂度在 \(O(2^{40})\) 左右,显然是过不去的。
这里使用双向 dfs,我们从左上角和右下角分别做两次 dfs,并且让两个 dfs 在遍历到左下角到右上角的这条对角线上的时候停下,最后在这条对角线上综合两个 dfs 的结果计入答案即可。
在这里我把对角线上最后的统计操作放进了第二个 dfs 中,第一个 dfs 会在对角线上留下答案,在第二个 dfs 中我们一与这些答案接头就迅速记入答案。
详情见代码。
代码
#include <bits/stdc++.h>
using namespace std;
map<long long, long long> dp[450];
long long n, m, k, a[25][25];
void dfs1(int x, int y, long long now) {
if ((x + y) == (n + m) / 2 + 1)
dp[21 * x + y][now ^ a[x][y]]++;
//在边界处记下答案
else {
if (x < n)
dfs1(x + 1, y, now ^ a[x][y]);
if (y < m)
dfs1(x, y + 1, now ^ a[x][y]);
}
return;
}
long long sum = 0;
void dfs2(int x, int y, long long now) {
if ((x + y) == (n + m) / 2 + 1)
sum += dp[21 * x + y][k ^ now];
//如果到达对角线,将now所对应的k^now的答案计入答案即可
else {
if (x > 1)
dfs2(x - 1, y, now ^ a[x][y]);
if (y > 1)
dfs2(x, y - 1, now ^ a[x][y]);
}
return;
}
int main() {
scanf("%lld%lld%lld", &n, &m, &k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%lld", &a[i][j]);
dfs1(1, 1, 0); //从左上角开始做第一次dfs
dfs2(n, m, 0); //从右下角开始做第二次dfs
printf("%lld\n", sum);
return 0;
}