【ABC271F】XOR on Grid Path

首先你一路爆搜过去结果肯定是对的。

但是你从左上角走到右下角需要 \(2(n-1)\) 步,而每一步有两种选择,则总共有 \(2^{2(n-1)}\) 种路径搜不死你

如何优化呢?我们连接右上角和左下角,钦定这一条对角线上的点是“转折点”。

当我们的搜搜搜程序到达某个转折点时,就可以了!

再钦定一个计数器 \(f[x][y][val]\),表示从左上角到转折点 \((x,y)\) 时路径异或值为 \(val\) 的方案数。

由于异或有性质:\(a\oplus a=0\)\(\oplus\) 表示异或,即 ^ 运算符)

那么只要我们再从右下角搜搜搜到转折点,然后看能结出几条路就可以了。

#include <map>
#include <stdio.h>
int val[25][25];
int n,i,j;
long long res;
std::map<long long,int> f[25][25];//注意long long。
const int dx[5]={0,1,0,-1,0};
const int dy[5]={0,0,1,0,-1};
inline void fill(int x,int y,int dep)//从左上角搜!搜!搜!
{
	dep^=val[x][y];//注意这两段程序中这句话的位置是不同的。
	if(x+y==n+1)
	{
		++f[x][y][dep];
		return ;
	}
	fill(x+dx[1],y+dy[1],dep);
	fill(x+dx[2],y+dy[2],dep);
	return ;
}
inline void solve(int x,int y,int dep)//从右下角搜!搜!搜!
{
	if(x+y==n+1)//对角线性质:行列数相加为n+1.
	{
		res+=f[x][y][dep];//现在路上是dep,dep^dep=0
		return ;
	}
	dep^=val[x][y];
	solve(x+dx[3],y+dy[3],dep);
	solve(x+dx[4],y+dy[4],dep);
}
int main()
{
	scanf("%d",&n);
	for(i=1;i<=n;++i)
		for(j=1;j<=n;++j)
			scanf("%d",val[i]+j);
	fill(1,1,0);
	solve(n,n,0);
	printf("%lld",res);
	return 0;
}
posted @ 2023-02-05 17:35  Syara  阅读(18)  评论(0编辑  收藏  举报