建议访问原文出处,获得更佳浏览体验。
原文出处:https://hyp1231.github.io/2018/07/17/20180717-cf1006f/
题意
给定
n×m
n
×
m
的矩阵,以及一个整数
k
k
。
定义路径为,从 出发,只能向右 / 下方走,到达
(n,m)
(
n
,
m
)
的行走方案。
定义路径的权重为,路径经过的整数的
xor
x
o
r
之和。
求权重为
k
k
的路径的条数。
链接
题解
定义从路径一端到 的某条路径上的整数的 xor x o r 之和为 (x,y) ( x , y ) 处的状态。
由于 n n 和 的范围均为 20 20 之内,考虑暴力搜索。对于每个位置,之后都有两种状态转移(向下 / 向右)。因此我们将矩阵按照 m+n m + n 的值进行分层,如果从起点开始 bfs b f s ,易知每次状态转移使层数加一,每一层的状态数不超过上一层的二倍,故直接 bfs b f s 的状态数不超过 2m+n 2 m + n ,但这个量级是我们不能接受的。
而考虑起点和终点的值都是唯一且确定的,我们可以从起点和终点同时采用 bfs b f s 。因此我们规定 m+n2 m + n 2 为中心层,两个 bfs b f s 一到中心层则停止搜索,这样在中心层,如果有重合的状态则说明有合法路径。
为了记录合法路径的数目,我们需要记录某一个 bfs b f s (这里不妨设为从起点出发的)到达状态 val v a l 的路径数。在实现上,我们使用 STL S T L 库中的 map m a p ,形成状态到路径数的映射。这样先实现从起点出发的 bfs b f s ,得到中间层每个位置各个状态的路径数;再做另一个 bfs b f s ,对于每个到中间层的状态,把第一个 bfs b f s 中计算出的该状态对应的路径数加到总的 ans a n s 中。
这样搜索到中间层的状态数不超过 2m+n2 2 m + n 2 , map m a p 的复杂度 O(log2m+n2)=O(m+n2log2)=O(m+n2) O ( log 2 m + n 2 ) = O ( m + n 2 log 2 ) = O ( m + n 2 ) ,总复杂度 O(m+n2⋅2m+n2) O ( m + n 2 ⋅ 2 m + n 2 ) 。
代码
#include <iostream>
#include <queue>
#include <map>
typedef long long LL;
const int N = 20;
struct State {
int x, y;
LL val;
State(int x = 0, int y = 0, LL val = 0) : x(x), y(y), val(val) {}
};
int n, m, mid;
LL a[N][N], k;
// 记录中间层 状态->路径数 的映射
// 由于 x + y = (n + m) / 2,我们确定了 x 即可确定 y
// 因此 res[x][st] 代表中间层横坐标为 x 的点,状态为 st 的路径数目
std::map<LL, int> res[N << 1];
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
std::cin >> n >> m >> k;
mid = (n + m - 2) >> 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
std::cin >> a[i][j];
}
}
LL ans = 0;
std::queue<State> que1, que2;
que1.push(State(0, 0, a[0][0]));
while (!que1.empty()) {
State tmp = que1.front(); que1.pop();
int x = tmp.x, y = tmp.y;
LL val = tmp.val;
if (x + y == mid) { // 到达中心线
if (res[x].count(val)) {
++res[x][val];
} else {
res[x][val] = 1;
}
} else {
if (x + 1 != n) que1.push(State(x + 1, y, val ^ a[x + 1][y]));
if (y + 1 != m) que1.push(State(x, y + 1, val ^ a[x][y + 1]));
}
}
que2.push(State(n - 1, m - 1, k));
while (!que2.empty()) {
State tmp = que2.front(); que2.pop();
int x = tmp.x, y = tmp.y;
LL val = tmp.val;
if (x + y == mid) {
ans += res[x][val];
} else {
if (x - 1 >= 0) que2.push(State(x - 1, y, val ^ a[x][y]));
if (y - 1 >= 0) que2.push(State(x, y - 1, val ^ a[x][y]));
}
}
std::cout << ans << std::endl;
return 0;
}