9-9华为笔试,3题AK

9-9华为笔试,3题AK

num1

大概思路:题目要求的是,第一个完美排列出现的位置,然后看数据范围,给出的数值最大是5,那么我们可以考虑,把这两个串合成一个,A[i] = a[i] * 6 + b[i];,
对于给出的大串也是如此B[i] = c[i] * 6 + d[i]; 然后就是直接kmp匹配,找到出现的第一个位置,变成kmp模板题

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

const int mn = 1e6 + 10;

int n, m;
int nx[mn];

void cal_next(int b[])
{
 memset(nx, 0, sizeof nx);
 nx[0] = -1;
 int k = -1;
 int j = 0;
 while (j < m)
 {
  if (k == -1 || b[j] == b[k])
  {
   j++; k++;
   nx[j] = k;
  }
  else
   k = nx[k];
 }
}

int KMP(int a[], int b[])
{
 cal_next(b);

 int i = 0, j = 0;
 while (i < n && j < m)
 {
  if (j == -1 || a[i] == b[j]) i++, j++;
  else j = nx[j];
 }
 if (j >= m) return i - m + 1;
 else return 0;
}

int a[mn], b[mn];
int c[mn], d[mn];
int A[mn], B[mn];

int main()
{
 cin >> m;
 for (int i = 0; i < m; i++) scanf("%d", &a[i]);
 for (int i = 0; i < m; i++) scanf("%d", &b[i]);
 for (int i = 0; i < m; i++)
  A[i] = a[i] * 6 + b[i];


 cin >> n;
    for (int i = 0; i < n; i++) scanf("%d", &c[i]);
    for (int i = 0; i < n; i++) scanf("%d", &d[i]);
 for (int i = 0; i < n; i++)
  B[i] = c[i] * 6 + d[i];

    cout << KMP(B, A) << endl;

    return 0;
}

/*
2
3 4
3 4
8
0 0 0 0 3 4 0 0
0 0 0 0 3 4 0 0

*/

num2

裸的记忆化搜索,由于有单调性,不难想到DP。要计算某点A为起点的最长水沟长度lenA,先计算A的上下左右四个点B1\B2\B3\B4中比A低的点如B1、B2的水沟长度,计B1、B2为起点的最长水沟长度为lenB1、lenB2,则lenA = max(lenB1, lenB2) + 1,如果四周没有比A低的点则lenA = 1;

void DFS(int nowx,int nowy)
{
    if(dp[nowx][nowy]) return ;
    dp[nowx][nowy]=1;
    for(int i=0;i<=3;i++){
        int tx=nowx+x[i];
        int ty=nowy+y[i];
        if(tx>=1&&tx<=N&&ty>=1&&ty<=M&&a[nowx][nowy]>a[tx][ty]){
            DFS(tx,ty);
            dp[nowx][nowy]=max(dp[nowx][nowy],dp[tx][ty]+1);
        }
    }
    ans=max(ans,dp[nowx][nowy]);
}
for(int i=1;i<=N;i++)
   for(int j=1;j<=M;j++)
       DFS(i,j);

num3:

题意:给定一棵树,问最大亦或路径。
思路: 首先最大亦或,得需要用01Trie来做,如果你不会,那么这题应该就不会了。(劝退)
1,先介绍一下什么是Trie字典树:给你一本字典,让你查里面是否有某个单词,比如‘bcd’,你应该会看是否有b开头的单词,然后看‘bc’,然后看‘bcd’。 这个的话,想象一个树,从根往下,连起来就是这个单词。 我们把单词都插入这个树里,就形成了一颗字典树,如果查单词,那么就从根向下查即可。 这个相比hash的好处:(1)不会出现hash那样的差错。(2)前缀重复的地方可以节省空间。

2,其次是要知道亦或的性质: a到b的亦或=a到根的亦或XORb到根的亦或。 所以我们求出每个点到根的亦或值,假设现在的亦或为a[]。 现在就是要在这些a[]里面找两个数,使得他们的亦或最大。

3,知道的性质2,和字典树。 我们就可以着手处理此题了。不过我们现在不是找单词,而是找最大亦或,我们把a[]集合的数都变为2进制,按高位到地位一次插入树里,现在要在集合里面找最大亦或,等效于高位尽可能不一样。 所以得尽量走反向,即我如果是1,我就看儿子节点是否有0…这在query里面得到体现。

#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int Laxt[maxn],Next[maxn],To[maxn],cnt;
int W[maxn],ch[maxn*30][2],ans,node;
void add(int u,int v)
{
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}
void dfs(int u,int f)
{
    W[u]=W[f]^W[u];
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i];
        if(To[i]==f) continue;
        dfs(To[i],u);
    }
}
int query(int x)
{
    int now=0,res=0;
    for(int i=30;i>=0;i--){
        int t=(x>>i)&1;
        if(ch[now][1-t]) res+=(1<<i),now=ch[now][1-t];
        else now=ch[now][t];
    }
    return res;
}
int insert(int x)
{
    int now=0;
    for(int i=30;i>=0;i--){
        int t=(x>>i)&1;
        if(!ch[now][t])  ch[now][t]=++node;
        now=ch[now][t];
    }
}
int main()
{
    int N,id,x;
    scanf("%d",&N);
    for(int i=1;i<=N;i++){
        scanf("%d",&id);
        scanf("%d",&W[id]);
        for(int j=1;j<=2;j++){
           scanf("%d",&x);
           if(x!=-1){
               add(id,x);
               add(x,id);
           }
        }
    }
    dfs(1,0);
    for(int i=1;i<=N;i++){
        if(i>1) ans=max(ans,query(W[i]));
        insert(W[i]);
    }
    printf("%d\n",ans);
    return 0;
}
/*
5
1 1 2 3
2 4 -1 -1
3 2 -1 4
4 5 -1 5
5 3 -1 -1
*/
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值