CF1006F Xor-Paths

发布于 2020-08-16  2.58k 次阅读


题面

题意

问你矩阵所有从左上角到右下角的路径中异或和等于 $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;
}

我缓慢吐出一串啊吧啊吧并不再想说话