牛客练习赛37 C(双向dfs+字典树)

题目要求在n*n的矩阵中从(1,1)走到(n,n),每步走下或右,途中数字与自身数字异或,求最小异或值。暴力搜索复杂度过高,采用分治策略,将路径分为两段,每段复杂度为C2010,并利用字典树计算最大异或和。" 106294265,8612004,Django博客分页实现与前端优化,"['Python', 'web开发', 'Django框架', '前端设计', '博客建设']
摘要由CSDN通过智能技术生成

题目链接:C 筱玛的迷阵探险
题意:给定一个n*n( n &lt; = 20 n&lt;=20 n<=20)大小的矩阵,矩阵中的每个点上有一个数字,初始时,你自身有一个数字,现在让你从(1,1)走到(n,n),每次只能向下或向右走,将路径上的数字以及你自身的数字异或起来,问最小的异或值为多少。
首先考虑数据最值,直接大力搜索的话复杂度为 C 40 20 C_{40}^{20} C4020,复杂度很高。
所以我们可以将路径拆为从(1,1)走20步到(x,y),再从(x,y)走20步道(n,n),这两个分开计算复杂度为: 2 ∗ C 20 10 2*C_{20}^{10} 2C2010,路径计算最大异或和的话,就需要用到字典树,我们枚举行号,建立字典树,计算答案即可。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int maxn=6e6+7;
#define int long long
int trie[maxn][2];

int tot=1;

void insert(int x){
    int p=1,id;
    for(int i=30;i>=0;--i){
        id=((x>>i&1)?1:0);
        if(!trie[p][id]) trie[p][id]=++tot;
        p=trie[p][id];
    }
}

int myfind(int x){
    int p=1,id;
    int res=0;
    for(int i=30;i>=0;--i){
        id=((x>>i&1)?1:0);
        if(trie[p][!id]) res+=(1<<i),p=trie[p][!id];
        else p=trie[p][id];
    }
    return res;
}

void init(){
    memset(trie,0,sizeof(trie));
    tot=1;
}
int n;

int a[29][29];

int getid(int x,int y){ return x*n+y; }
vector<int> v1[29],v2[29];
bool check(int x,int y){
    if(x>=1&&x<=n&&y>=1&&y<=n) return 1;
    return 0;
}
int e;
void dfs1(int x,int y,int step,int val){
    if(step==n){
        v1[x].push_back(val^e);
        return ;
    }
    if(check(x,y+1)) dfs1(x,y+1,step+1,val^a[x][y+1]);
    if(check(x+1,y)) dfs1(x+1,y,step+1,val^a[x+1][y]);
}

void dfs2(int x,int y,int step,int val){
    if(step==n){
        v2[x].push_back(val);
        return ;
    }
    if(check(x-1,y)) dfs2(x-1,y,step+1,val^a[x-1][y]);
    if(check(x,y-1)) dfs2(x,y-1,step+1,val^a[x][y-1]);
}

signed main(){
    scanf("%lld%lld",&n,&e);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j) scanf("%lld",&a[i][j]);
    if(n==1){
        printf("%lld\n",e^a[1][1]);
        return 0;
    }
    dfs1(1,1,1,a[1][1]);
    dfs2(n,n,1,a[n][n]);
    int maxx=0;
    for(int i=1;i<=n;++i){
        init();
        for(int j=0;j<v2[i].size();++j) insert(v2[i][j]);
        for(int j=0;j<v1[i].size();++j) maxx=max(maxx,myfind(v1[i][j]));
    }

    printf("%lld\n",maxx);

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值