Step1 Problem:
给你 n*m 的矩阵,从 (1, 1) 到 (n, m) 只能往下和往右走,路径上的数异或起来等于 k 的路径数。
数据范围:
1<=n, m <= 20. 0 <= k <= 1e18. 0 <= a[i][j] <= 1e18.
Step2 Ideas:
n, m 很小,我特别打了个表,从 (1, 1) 到 (11, 11) 的路径方案数 = 184756。
所以我们可以折半搜索:
为什么选择到 (n+m+2)/2 而不是 (n+m-2)/2,因为 (n+m-2)/2 矩阵太小的话,就没有满足条件的点。
第一遍搜索:从 (1, 1) 到 (n+m+2)/2(包含) 的格子 每个格子构成 sum 的路径方案数存起来。
第二遍搜索:从 (n, m) 到 (n+m+2)/2(不包含) 的格子 异或 k 构成 sum ,将之前构成 sum 存起来的方案数的 和为结果。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n, m;
ll a[25][25];
map<ll, ll> vis[25];
void dfs1(int u, int v, ll sum)//求 (1, 1) 到 (n+m+2)/2 构成 sum 的路径方案数
{
if(u+v == (n+m+2)/2) {
vis[u][sum]++;
return ;
}
if(u <= n)
dfs1(u+1, v, sum^a[u+1][v]);
if(v <= m)
dfs1(u, v+1, sum^a[u][v+1]);
}
ll ans;
void dfs2(int u, int v, ll sum)//(n, m) 到 (n+m+2)/2
{
if(u+v == (n+m+2)/2) {//构成 sum 就加起来。
ans += vis[u][sum];
return ;
}
if(u-1 >= 1)
dfs2(u-1, v, sum^a[u][v]);
if(v-1 >= 1)
dfs2(u, v-1, sum^a[u][v]);
}
int main()
{
ll k;
scanf("%d %d %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, a[1][1]);
ans = 0;
dfs2(n, m, k);//需要异或 k
printf("%lld\n", ans);
return 0;
}