首页 > 华为9.9笔试 第二题第三题题解
头像
灯火微凉。
编辑于 2020-09-09 21:55
+ 关注

华为9.9笔试 第二题第三题题解

第二题
将每个方格视为一个点 若两个相邻点满足一个点的值小于另外一个点 就连一条有向边 显然这个图肯定是个DAG(有向无环图) 在DAG跑一遍最长路dp就可以了 复杂度((4*n*n+n*n))
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <vector>
#define fir first
#define se second
#define ll long long
#define pb push_back
#define mp make_pair
#define ull unsigned long long
#define cl(a, b) memset(a, b, sizeof(a))
#define quickio(a) ios::sync_with_stdio(a)
#define datatest() freopen("data.in", "r", stdin)
#define makeans() freopen("data.out", "w", stdout)
#define makedata() freopen("data.in", "w", stdout)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pdd pair<double, double>
using namespace std;
const int maxn = 1000 + 10;
const int maxm = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int maxblock = sqrt(maxn) + 10;
const double eps = 1e-7;
const ll INF = 1e16;
struct Edge {
  int u, v, next;
} edge[maxn * maxn * 4];
int head[maxn * maxn];
int tot = 0;
int in[maxn * maxn];
void init() {
  cl(head, -1);
  cl(in, 0);
  tot = 0;
}
void addedge(int u, int v) {
  edge[tot] = Edge{u, v, head[u]};
  head[u] = tot++;
  in[v]++;
}
int n, m;
int a[maxn][maxn];
int id[maxn][maxn];
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
int legal(int x, int y) { return (x >= 1 && x <= n && y >= 1 && y <= m); }
int dp[maxn * maxn];
int main() {
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]);
  }
  int now_id = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) id[i][j] = ++now_id;
  }
  init();
  for (int x = 1; x <= n; x++) {
    for (int y = 1; y <= m; y++) {
      for (int i = 0; i < 4; i++) {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if (legal(xx, yy) && a[x][y] < a[xx][yy]) {
          addedge(id[x][y], id[xx][yy]);
        }
      }
    }
  }
  std::queue<int> q;
  cl(dp, 0);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (!in[id[i][j]]) {
        q.push(id[i][j]);
        dp[id[i][j]] = 1;
      }
    }
  }
  int Max = 0;
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    Max = std::max(Max, dp[u]);
    for (int i = head[u]; ~i; i = edge[i].next) {
      int v = edge[i].v;
      dp[v] = std::max(dp[v], dp[u] + 1);
      in[v]--;
      if (!in[v]) {
        q.push(v);
      }
    }
  }
  printf("%d\n", Max);
  return 0;
}
第三题
假设根为root,令从root到i节点路径的异或为sum[i],那么路径(u,v)的异或值就是sum[u]^sum[v]
于是,可以从根节点dfs,并快速查询满足sum[u]^sum[v]的最大的v即可
查询可以采用01字典树完成
复杂度((n+e)*30)
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <vector>
#define fir first
#define se second
#define ll long long
#define pb push_back
#define mp make_pair
#define ull unsigned long long
#define cl(a, b) memset(a, b, sizeof(a))
#define quickio(a) ios::sync_with_stdio(a)
#define datatest() freopen("data.in", "r", stdin)
#define makeans() freopen("data.out", "w", stdout)
#define makedata() freopen("data.in", "w", stdout)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pdd pair<double, double>
using namespace std;
const int maxn = 1e5 + 10;
const int maxm = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int maxblock = sqrt(maxn) + 10;
const double eps = 1e-7;
const ll INF = 1e16;
const int N = 1e5 * 30 + 10;
struct Trie {
  using LL = long long;
  LL ch[N][2], sz;
  LL val[N], ed[N];
  void Init() {
    memset(ch[0], 0, sizeof(ch[0]));
    ed[0] = 0;
    sz = 1;
  }
  void Insert(LL x) {
    int u = 0;
    for (int i = 40; i >= 0; i--) {
      int v = (x & (1ll << i)) > 0 ? 1 : 0;
      if (!ch[u][v]) {
        memset(ch[sz], 0, sizeof(ch[sz]));
        val[sz] = 0;  //每个节点的附加信息
        ed[sz] = 0;
        ch[u][v] = sz++;  //存储该节点的编号sz
      }
      u = ch[u][v];
      val[u]++;
    }
    ed[u] = x;  //最后一个节点记录数值
  }
  void Delete(LL x) {
    int u = 0;
    for (int i = 40; i >= 0; i--) {
      int v = (x & (1ll << i)) > 0 ? 1 : 0;
      u = ch[u][v];
      val[u]--;
    }
    // ed[u]=0;//可能有重复数字,若置为0后该位置的另一个数字也被删除了
  }
  LL Search(LL x) {
    int u = 0;
    for (int i = 40; i >= 0; i--) {
      int v = (x & (1ll << i)) > 0;  //判断条件
      if (ch[u][!v] && val[ch[u][!v]]) {
        u = ch[u][!v];
      } else if (ch[u][v] && val[ch[u][v]]) {
        u = ch[u][v];
      } else
        return x ^ ed[u];
    }
    return x ^ ed[u];
  }
} trie;
int n;
ll w[maxn];
vector<int> g[maxn];
int in[maxn];
ll Max = 0;
ll sum[maxn];
void dfs(int u, int fa) {
  if (fa == -1) {
    sum[u] = w[u];
  } else {
    sum[u] = sum[fa] ^ w[u];
  }
  // cout << u << " " << sum[u] << endl;
  ll query = trie.Search(sum[u]);
  trie.Insert(sum[u]);
  Max = max(Max, query);
  Max = max(Max, sum[u]);
  for (int i = 0; i < g[u].size(); i++) {
    int v = g[u][i];
    if (fa == v) continue;
    dfs(v, u);
  }
  trie.Delete(sum[u]);
}
int main() {
  scanf("%d", &n);
  for (int i = 0; i <= n; i++) g[i].clear();
  cl(in, 0);
  for (int i = 1; i <= n; i++) {
    int id, l, r;
    ll weight;
    scanf("%d %lld %d %d", &id, &weight, &l, &r);
    w[id] = weight;
    if (l != -1) {
      g[id].push_back(l);
      g[l].push_back(id);
      in[l]++;
    }
    if (r != -1) {
      g[id].push_back(r);
      g[r].push_back(id);
      in[r]++;
    }
  }
  int rt = -1;
  for (int i = 1; i <= n; i++) {
    if (!in[i]) {
      rt = i;
      break;
    }
  }
  trie.Init();
  // trie.Insert(0);
  dfs(rt, -1);
  printf("%lld\n", Max);
  return 0;
}
/*
5
1 1 2 3
2 4 -1 -1
3 2 -1 4
4 5 -1 5
5 3 -1 -1
*/


全部评论

(0) 回帖
加载中...
话题 回帖

相关热帖

历年真题 真题热练榜 24小时
技术(软件)/信息技术类
查看全部

近期精华帖

热门推荐