Codeforces Round #498 (Div. 3) F. Xor-Paths(折半搜索

链接
题意:问从1,1到n,m有多少条异或值为k的路径。
解析:
直接暴力为2^40 用折半搜索会降到2^21,
我们只需记录达到中间值x+y==(n+m+2)/2的异或值,反向搜索的时候捕获这个值即可,
需要注意的是中间点被异或了两次,所以要再异或一次

#include<bits/stdc++.h>
using namespace  std;
#define ll long long
#define pb push_back
#define inf 2099999999
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep1(i,a,b) for(int i=a;i>=b;i--)
const int N=20+10;
ll arr[N][N];
map<ll,ll>mp[N][N];
ll n ,m ,k,ans=0;
void dfs_pre(ll x,ll y ,ll num)
{
    if(x+y==(n+m+2)/2)
    {
        mp[x][y][num]++;
        return ;
    }
    if(x<n) dfs_pre(x+1,y,num^arr[x+1][y]);
    if(y<m) dfs_pre(x,y+1,num^arr[x][y+1]);
}
void dfs(ll x,ll y ,ll num)
{
    if(x+y == (n+m+2)/2)
    {
        ans+=mp[x][y][num^k^arr[x][y]];//由于中间点被异或了两次
        //这里要异或回去
        return ;
    }
    if(x>1) dfs(x-1,y,num^arr[x-1][y]);
    if(y>1) dfs(x,y-1,num^arr[x][y-1]);
}
int main()
{
    #ifdef LOCAL_DEFINE
        freopen("D://rush.txt", "r", stdin);
    #endif
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>n>>m>>k;
    ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
             cin>>arr[i][j];
    }
    dfs_pre(1,1,arr[1][1]);
    dfs(n,m,arr[n][m]);
    cout<<ans<<endl;
}
posted @ 2018-07-20 16:57  ffgcc  阅读(92)  评论(0编辑  收藏  举报