Codeforces Round #498 (Div. 3) F. Xor-Paths (双端DFS+思维)

题目链接

题意:给出一个n*m的矩阵,矩阵中每个位置都有一个值,问你从左上角(1,1)这个点的值异或到右下角(n,m)这个点的值为K的情况数量有多少(每次只能向下或向右走一格);

题解:对于这个问题,最大数据20*20的矩阵中,从左上角到异或到右下角能出现的情况数目太多,如果暴力DFS或者BFS都可能会爆时间(题目没有要求取模说明答案数量可观,起码可以用longlong存的下),那么需要解决的是爆时间的问题,这里我们可以技巧性的将这个矩阵尽量的对半分,采用双端DFS的方式将时间开个根号。

           具体是先从左上角DFS到x+y==max(n,m)处(起始值为0),将数据存入三维的map中,map【x】【y】【当前异或值】=数量 .然后再一次从右下角DFS到同样的x+y==max(n,m)处(起始值为K),然后每次都ans+=map【x】【y】【当前异或值】即可。

             因为X^Y=K,那么有Y=K^X,反向求得到需要的Y即可,所以上面ans是加上当前点的当前异或值的数量。

代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<map>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
ll mp[25][25];
ll k, ans;
int n, m, MAX;
map<ll, ll>q[25][25];
void dfs_1(int x, int y,ll s) {
	s ^= mp[x][y];
	if (x + y == MAX) {
		q[x][y][s]++;
		return;
	}
	if (x + 1 <= n)	dfs_1(x + 1, y, s);
	if (y + 1 <= m) dfs_1(x, y + 1, s);
}
void dfs_2(int x, int y, ll s) {
	if (x + y == MAX) {
		ans += q[x][y][s];
		return;
	}
	s ^= mp[x][y];
	if (x - 1 >= 1)	dfs_2(x - 1, y, s);
	if (y - 1 >= 1) dfs_2(x, y - 1, s);
}
int  main(){
	scanf("%d%d%lld", &n, &m, &k);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%lld", &mp[i][j]);
	if (n == 1 && m == 1) {
		if (mp[1][1] == k)
			printf("1\n");
		else
			printf("0\n");
		return 0;
	}
	MAX = max(n, m);
	dfs_1(1, 1, 0);
	dfs_2(n, m, k);
	printf("%lld\n", ans);
	return  0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81083349