Codeforces1006F-Xor-Paths-折半搜索

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:

 原题目描述在最下面。
 题目大意就是给你一个n*m的矩阵,每个点都有权值。问你从点[1, 1]走到[n, m]路径上所有点权异或和为k的路径有多少种。注意只能向下和向右走。

思路:

 大佬说这题暴力就行了。然而我最暴力的搜索方法却超时了。
 这才了解到原来大佬的暴力是折半搜索。

 折半搜索就是把最暴力从[1, 1]搜索到[n, m]的搜索方法,改成,从[1, 1]搜索到中间一个过程,再从[n, m]搜索到中间那个过程。这样的两次搜索,复杂度降低了居多。

 我选取的中间过程是一条斜对角线的平行线:i + j = (n + m)/2 + 1.
 正向搜索过程中用一个map记录搜索到低i行异或和值为x的数量。
 反向搜索过程就是计数了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+7;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int n, m;
LL k, ans, ar[25][25];
unordered_map<LL, LL> cnt[N];
void dfs1(int i, int j, LL val){
  if(i > n || j > m || i < 1 || j < 1)return;
  val ^= ar[i][j];
  if(i + j == (m + n) / 2 + 1){
    //printf("%d %d %lld\n", i,j,val);
    cnt[i][val]++;
    return;
  }
  dfs1(i, j + 1, val);
  dfs1(i + 1, j, val);
}
void dfs2(int i, int j, LL val){
  if(i > n || j > m || i < 1 || j < 1)return;
  if(i + j == (m + n) / 2 + 1){
    ans += cnt[i][k ^ val];
    return;
  }
  val ^= ar[i][j];
  dfs2(i - 1, j, val);
  dfs2(i, j - 1, val);
}
int main(int argc, char const *argv[]){
  while(~scanf("%d%d%lld", &n, &m, &k)){
    for(int i = 1; i <= n; ++i){
       cnt[i].clear();
      for(int j = 1; j <= m; ++j){
        scanf("%lld", &ar[i][j]);
      }
    }
    ans = 0;
    dfs1(1, 1, 0);
    dfs2(n, m, 0);
    printf("%lld\n", ans);
  }  
  return 0;
}


题目描述:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81090218
今日推荐