zoukankan      html  css  js  c++  java
  • CodeForces 1006F Xor-Paths|Meet in the middle

    题目链接

    题目大意:给一个 (n imes m) 的网格图。每个点有一权值 (a_{i,j}),现在要从 ((1,1)) 走到 ((n,m)),且仅能向右或向下,求路径经过的点的权值异或和恰好为(k)的方案数。
    (1 le n,m le 20; 0 le k le 10^{18})

    题目思路:
    看上去找不到什么算法去解决本题,那么遇事不决上暴搜,复杂度约为 (2^{n+m}),显然不能通过,并且这是CF题没部分分
    但是我们还是找不到什么解法,只好考虑优化搜索(这一步在考场上尤为重要)。
    我们发现,在本题中,我们既可以从起点开始搜索,也可以从终点开始搜索。显然这是等价的。这条性质等下将用到。
    现在引入一个概念:双向搜索/折半搜索/Meet in the middle。顾名思义,其方法是分别从起点和终点开始,做一半路程的搜索,并保存下结果,最后进行合并。这个方法的原理就是上文从起点搜和从终点搜等价的性质。
    于是,搜索的时间复杂度由 (2^{n+m}) 变为 (2 imes 2^{frac{n+m}{2}}),可以接受。
    当然,合并答案也是很重要的一步。考虑如何快速得出答案:我们使用(map)来保存每个中间点的答案,从起点搜时记录,从终点搜时取出即可。由于结果数尚不算多,因此也可以接受
    上代码

    #include<bits/stdc++.h>
    using namespace std;
    map<long long,int> f[30][30];
    long long n,m,k,z[30][30],a[30][30],ans,t;
    void q_dfs(int x,int y,long long kk)
    {	
    	if (x>n||y>m) return ;
    	if (x+y==((n+m+2)>>1)) 
    	{f[x][y][kk]++;return ;}
    	q_dfs(x+1,y,kk^a[x+1][y]);
    	q_dfs(x,y+1,kk^a[x][y+1]);
    }//从起点开始搜
    void h_dfs(int x,int y,long long kk)
    {
    	if (x<1||y<1) return ;
    	if (x+y==((n+m+2)>>1))
    	{
    		if (f[x][y].find(k^(kk^a[x][y]))==f[x][y].end()) return ;
    		ans+=f[x][y][k^(kk^a[x][y])];
    		return ;
    	}
    	h_dfs(x-1,y,kk^a[x-1][y]);
    	h_dfs(x,y-1,kk^a[x][y-1]);
    }//从终点开始搜
    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]);
    	    f[i][j].clear();
    	  }
    	q_dfs(1,1,a[1][1]);
    	h_dfs(n,m,a[n][m]);
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    instruments 内存泄漏
    ios常用数学函数
    正则表达式
    view设置成圆角
    关于新浪微博注销后自动登录的问题
    根据视频地址获取某一帧的图像
    使用DES加解密
    实现通讯录的查询与删除
    iOS 动画效果
    iOS 文字下划线
  • 原文地址:https://www.cnblogs.com/fmj123/p/14082531.html
Copyright © 2011-2022 走看看