阿里巴巴2021编程题(四星)1-5题题解

题目链接2021阿里巴巴校招笔试真题_Java工程师、C++工程师_牛客网 (nowcoder.com)

目录

第一题

第二题

第三题

第四题

第五题


第一题

思路:

先对物品进行排序,根据x的从小到大,y从大到小的规则,y从大到小是为了防止最长上升子序列中有x相同的情况

求y的最长上升子序列长度,用lower_bound函数,贪心+二分思想

#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
typedef struct {
    int a;
    int b;
} pii;

pii s1[100100];
int d[100100], n;
const int INF = 0x3f3f3f3f;

bool cmp(pii& a, pii& b) {
    if (a.a != b.a) return a.a < b.a;
    return a.b > b.b;
}

int get_result(pii s[]) {
    sort(s + 1, s + 1 + n, cmp);
    fill(d, d + n + 1, INF);
    int result = 1;
    for (int i = 1; i <= n; i++) {
        int j = lower_bound(d, d + n + 1, s[i].b) - d;
        result = max(result, j + 1);
        d[j] = s[i].b;
    }
    if (result == 1) return 0;
    else return result;

}

int main() {
    int t;
    cin >> t;
    while (t--) {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> s1[i].a;
        }
        for (int i = 1; i <= n; i++) {
            cin >> s1[i].b;
        }
        printf("%lld\n", get_result(s1));
    }
}

第二题

思路:

线性dp,先推出公式x^n+y^n=(x+y)(x^{n-1}+y^{n-1})-xy(x^{n-2}+y^{n-2})

x+y=A xy=B

dp[n]=A*dp[n-1]-B-dp[n-2]

#include <iostream>
using namespace std;

typedef long long ll;
const ll mod=1e9+7;
ll dp[100010];
int main() {
    int t;
    cin>>t;
    while (t--) { // 注意 while 处理多个 case
        int a,b,n;
        cin>>a>>b>>n;
        dp[1]=a;
        dp[2]=a*a-2*b;
        for(int i=3;i<=n;i++)
        dp[i]=((a*dp[i-1])%mod-(b*dp[i-2])%mod+mod)%mod;
        cout<<dp[n]<<"\n";
    }
}

第三题

思路:

树形dp,一颗节点数为n的数的方案数是由其根节点的左右子树方案数决定的,还需要考虑树的高度,因此dp要考虑第二维高度

dp[i][j]表示结点个数为i,高度小于等于j的方案数

推导公式则为dp[i][j]+=dp[i-k-1][j-1]*dp[k][j-1]  0<=k<=i-1

#include <iostream>
using namespace std;

typedef long long ll;
const ll mod = 1e9+7;
ll dp[55][55];
int main() {
    int m,n;
    cin>>n>>m;
    for(int i=0;i<=m;i++)
    dp[0][i]=1;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            for(int k=0;k<=i-1;k++)
            {
                dp[i][j]=(dp[i][j]+(dp[i-k-1][j-1]*dp[k][j-1])%mod)%mod;
            }
        }
    
    cout<<dp[n][m];
}

第四题

 思路:

一眼BFS,dp[i][j]表示走到i,j坐标的最小步数,但是队列里得包含对称飞行器的使用次数

#include <iostream>
#include <queue>
using namespace std;

typedef struct {
    int x, y, p;
} pii;

const int INF = 0x3f3f3f3f;
int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
int dp[510][510];
queue<pii> q;
string s[510];
int main() {
    int n, m, sx, sy, fx, fy;
    cin >> n >> m;

    for (int i = 0; i < n; i++)
        cin >> s[i];

    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            dp[i][j] = INF;
            if (s[i][j] == 'S') {
                sx = i;
                sy = j;
            }
            if (s[i][j] == 'E') {
                fx = i;
                fy = j;
            }
        }

    dp[sx][sy] = 0;
    q.push({sx, sy, 5});

    while (!q.empty()) {
        pii tmp = q.front();
        q.pop();
        int x = tmp.x, y = tmp.y, p = tmp.p;
        for (int i = 0; i < 4; i++) {
            int xx = x + dx[i];
            int yy = y + dy[i];
            if (xx < 0 || xx >= n || yy < 0 || yy >= m || s[xx][yy]=='#') continue;
            if (dp[xx][yy] > dp[x][y] + 1) {
                dp[xx][yy] = dp[x][y] + 1;
                q.push({xx, yy, p});
            }
        }

        int syn_x = n - 1 - x, syn_y = m - 1 - y;
        if (dp[syn_x][syn_y] > dp[x][y] + 1 && p > 0 && s[syn_x][syn_y]!='#') {
            dp[syn_x][syn_y] = dp[x][y] + 1;
            q.push({syn_x, syn_y, p - 1});
        }
    }

    if (dp[fx][fy] == INF) cout << -1;
    else cout << dp[fx][fy];

}
// 64 位输出请用 printf("%lld")

第五题

(个人认为前五题最难的一道,前面四道还能做出来,这道只能看题解了,还是自己太菜了哇)

思路:

首先想到一点,一个人的abs(a,b)越大,代表如果要这个人合作的话,最小能力值是由这个人决定,可以理解为木桶效应(什么奇怪比喻?)

先把利用abs(a,b)从小到大排序

假设一个人i的能力值ai<bi,那么合作的总能力值就是a

假设合作的人能力值是aj,bj

ai+aj<bi+bj 

ai-bi<bj-aj

由于abs(aj-bj)<abs(ai-bi) 并且 ai<bi 所以上面不等式成立

所以只要再维护两个a和b的前缀最大值数组就可以了

#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;

typedef struct{
    int a,b,p;
}piii;

piii s[200010];
int pre_a[200010],pre_b[200010];
bool cmp(piii &a,piii &b)
{
    return a.p<b.p;
}
int main() {
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int a,b;
        cin>>a>>b;
        s[i].a=a;
        s[i].b=b;
        s[i].p=abs(a-b);
    }

    sort(s+1, s+1+n, cmp);

    for(int i=1;i<=n;i++)
    {
        pre_a[i]=max(pre_a[i-1],s[i].a);
        pre_b[i]=max(pre_b[i-1],s[i].b);
    }

    int result=0;
    for(int i=1;i<=n;i++)
    {
        result=max(result,s[i].a<s[i].b?s[i].a+pre_a[i-1]:pre_b[i-1]+s[i].b);
    }

    printf("%.1f",result/2.0);
}
// 64 位输出请用 printf("%lld")

总结:题目好难,后面五道题不想做了::>_<::,这就是大厂的含金量吗

猜你喜欢

转载自blog.csdn.net/qq_30798083/article/details/130203075
今日推荐