【笔试】美团2023年秋招第1场笔试(后端&数开&软件方向)

文章目录

      • [T1 小美玩排列](#T1 小美玩排列)
      • [T2 小美走公路](#T2 小美走公路)
      • [T3 小美切蛋糕](#T3 小美切蛋糕)
      • [T4 小美将字符串平铺成矩阵](#T4 小美将字符串平铺成矩阵)
      • [T5 小美染色](#T5 小美染色)

23秋招,美团笔试1(技术)

美团2024届秋招笔试第一场编程真题

时间:2023.08,牛客补题

美团是少有的整份卷子5题都是算法题的,20*5=100分,其他家一般会有408选择题再配2个编程题。

所以美团的T4、T5有时候会稍微有点卡点,我也没法保证每次都ak,有时候会有只能拿个九十几的情况,不过好在笔试可以做两次(虽然好像AK也不给面)

T1 小美玩排列

有一个排列,一共有n个数,还有特殊的两个数x和y,请你帮助小美判断x和y在排列中是否相邻,是则输出"Yes",不是则输出"No"

数据范围:

1 ≤ n ≤ 1e5

cpp 复制代码
//AC
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200010;
int p[maxn];
int main() {
    int n;  cin>>n;
    for(int i = 1; i <= n; i++){
        int x;  cin>>x;
        p[x] = i;
    }
    int x, y;
    cin>>x>>y;
    if(abs(p[x]-p[y])==1){
        cout<<"Yes\n";
    }else{
        cout<<"No\n";
    }
}

T2 小美走公路

现有一条环形公路,总共有n个站点,ai代表第i个站点与第i+1个站点之间的距离,特殊的,an表示第n个站点与第一个站点之间的距离。小美的出发地为x,目的地为y,请你求出x到y的最短距离

1 ≤ n ≤ 1e5

1 ≤ ai ≤ 1e9

cpp 复制代码
//AC
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 200010;
LL a[maxn], s[maxn];
int main() {
    LL n;  cin>>n;
    LL sum = 0;
    for(LL i = 1; i <= n; i++){
        cin>>a[i];
        sum += a[i];
    }
    LL x,y ;  cin>>x>>y;
    if(x > y)swap(x,y);
    LL res = 0;
    for(LL i = x; i < y; i++){
        res += a[i];
    }
    res = min(res, sum-res);
    cout<<res<<"\n";
}

T3 小美切蛋糕

现有一个n*m的蛋糕矩阵a,aij代表一小块蛋糕的美味度,现在小美要和一个好朋友分享蛋糕,因此需要把这个蛋糕矩阵切成两半,并且要求分成两半后的两块蛋糕的美味度尽可能相等,即求出分成两半后的两块蛋糕的abs(s1 - s2)的最小值,s1代表第一块蛋糕的美味度,s2代表第二块蛋糕的美味度。要求:必须保证每一小块蛋糕的完整性(即不能斜着切,如果把整个大蛋糕正着放)

1 ≤ n , m≤ 1e3

1 ≤ aij ≤ 1e5

cpp 复制代码
//AC
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a[1010][1010];
// LL b[1010][1010], c[1010][1010];
LL b[1010], c[1010];
int main() {
    LL n, m;  cin>>n>>m;
    LL sum = 0;
    for(LL i = 1; i <= n; i++){
        for(LL j = 1; j <= m; j++){
            cin>>a[i][j];
            b[i] += a[i][j];
            c[j] += a[i][j];
            sum += a[i][j];
            // b[i][j] += a[i][j-1];
            // c[i][j] += a[i-1][j];
        }
    }
    LL res = 1e9+10, tmp = 0;
    for(LL i = 0; i <= n; i++){
        tmp += b[i];
        res = min(res, abs((sum-tmp)-tmp));
    }
    tmp = 0;
    for(LL j = 0; j <= m; j++){
        tmp += c[j];
        res = min(res, abs((sum-tmp)-tmp));
    }
    cout<<res<<"\n";
}

T4 小美将字符串平铺成矩阵

现有一个长度为n的且仅包含小写字母的字符串s,小美想把这个字符串s平铺成一个xy的矩阵,要求xy == n,平铺的方法为:将字符串前y个字符按顺序放到第一行,将字符串第y+1到第2*y个字符按顺序放到第二行,以此类推。现规定矩阵的权值为连通量的数目,连通量代表的是从一个点出发,上下左右若存在相同字符则可以继续扩展该连通量(类似于一个岛屿,上下左右若存在相同的字符则可以扩展这个岛屿,或者可以理解为上下左右如果是相同字符则可以合并成一个连通量),求矩阵的最小权值

1 ≤ n ≤ 1e4

cpp 复制代码
//WA-最开始想直接set乱来,最后还是被迫换成dfs写
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int dx[] = {-1, 1, 0 ,0 };
int dy[] = {0, 0, -1, 1};
int main() {
    int n;  cin>>n;
    string s;  cin>>s;
    set<char>se;
    for(char ch : s){
        se.insert(ch);
    }
    // cout<<s[5]<<"\n";
    n = s.size();
    int res = 1e9+10;
    for(int i = 2; i < n; i++){
        if(n%i!=0)continue;
        int ts = 0;
        for(int j = 0; j < n; j++){
            set<char>tmp;
            int z = 0;
            int x = j/i, y = j%i;
            // tmp.insert(s[j]);
            int ok = 0;
            // z++;
            for(int k = 0; k < 4; k++){
                int nx = x+dx[k], ny = y+dy[k];
                if(nx<0||nx>=n/i || ny<0||ny>=i)continue;
                if(s[nx*i+ny]==s[j]){
                    // cout<<j<<" "<<nx<<" "<<ny<<" "<<s[nx*i+ny]<<" "<<s[j]<<"\n";
                    ok = 1;
                }
                
                // tmp.insert(s[nx*i+ny]);
                // z++;
                if(i==3 && j==2){
                    // cout<<nx<<" "<<ny<<" "<<s[nx*i+ny]<<" "<<s[j]<<"\n";
                    // cout<<x<<" "<<y<<" ";
                    // cout<<nx<<' '<<ny<<" asd\n";
                }
            }
            // if(j>=0){tmp.insert(s[j-1]); z++; }
            // if(j<n){tmp.insert(s[j+1]); z++; }
            // if(j-i>=0){tmp.insert(s[j-i]); z++; }
            // if(j+i<n){tmp.insert(s[j+i]); z++; }
            // cout<<i<<","<<j<<","<<tmp.size()<<" "<<z<<"\n";
            // for(char ch : tmp)cout<<ch; cout<<"\n";
            // if(tmp.size()==z){
            //     ts++;
            //     // cout<<i<<", "<<j<<"\n";
            // }
            if(ok!=1){
                ts++;
                // cout<<i<<", "<<j<<"\n";
            }
        }
        if(ts<res){
            // cout<<i<<" "<<ts<<"\n";
        }
        res = min(res, ts);
    }
    // cout<<se.size()<<"\n";
    cout<<(int)(res+se.size())<<"\n";
}
cpp 复制代码
//AC
//T4-AC
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int dx[] = {-1, 1, 0 ,0 };
int dy[] = {0, 0, -1, 1};
string s;
int n; 
int vis[10010];
// int ts = 0;
int ttt;
void dfs(int x, int y,int d){
        // cout<<x<<" "<<y<<"\n";
    for(int i = 0; i < 4; i++){
        int nx = x+dx[i], ny = y+dy[i];
        int nj = nx*d+ny;
        if(nx<0||nx>=n/d || ny<0||ny>=d || vis[nj])continue;
        if(s[nj] != s[ttt])continue;
        if(!vis[nj]){
            vis[nj] = 1;
            dfs(nx,ny,d);
        }
    }
}
int main() {
     cin>>n;
      cin>>s;
    int res = 1e9+10;
    for(int i = 1; i <= n; i++){
        if(n%i!=0)continue;
        int ts = 0;
        for(int j = 0; j < n; j++)vis[j] = 0;
        for(int j = 0; j < n; j++){
            int x = j/i, y = j%i;
            if(!vis[j]){
                // cout<<x<<' '<<y<<" asfd\n";
                ttt = j;
                dfs(x, y, i);
                ts++;
            }
        }
        // cout<<i<<" "<<ts<<"\n";
        res = min(res, ts);
    }
    // cout<<se.size()<<"\n";
    cout<<(int)(res)<<"\n";
}

T5 小美染色

现有一颗包含n个节点的树,节点i的权值为wi,di代表节点i相邻的节点集合。一开始所有节点均为白色,若两个相邻节点均为白色且权值的乘积为完全平方数则可以将两个节点都染成红色,问最多可以将多少个节点染成红色

1 ≤ n ≤ 1e5

1 ≤ wi ≤ 1e9

cpp 复制代码
// 输出0有10%(数据3/30),暴力+剪枝可以再多骗一部分
// AC 
//1、给出n个点和n-1条边的一棵树
//2、每次操作,相邻且白色且权值的乘积是完全平方数的,改成红色。求最多可以染多少个红。
//3、每个点有两个状态,选和不选,那么就是0/1DP了,又给了个树,也就是树上01DP
// u是根节点 ,i是子节点。不选根时,子节点的最大方案数统计上来就行,dp[u][0] += max(dp[i][0],dp[i][1])
// 选根,需要符合条件(is_sqrt(a[u]*a[i])==1)的子节点同时不被选中,那么dp[u][1]=dp[u][0]-max(dp[i][0],dp[i][1])+dp[i][0]+2,即回退这个点的记录,并更新成同时选中这个子节点和根节点的状态。
// 最后答案就是 max(dp[0][0],dp[0][1])
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn = 1e5 + 10;
LL a[maxn], c[maxn];
vector<LL>G[maxn];
LL dp[maxn][2];
LL res = 0;
int checksqrt(int x) { int d = sqrtl(x)+1e-7; return d*d == x; };
void dfs(LL u, LL f) {
    for (LL i : G[u]) {
        if (i == f)continue;
        dfs(i, u);
        dp[u][0] += max(dp[i][0], dp[i][1]);
        // if(checksqrt(a[i]*a[u])){  //需要先把所有子节点的dp状态都更新完了,确保dp[i][0/1]都是最优的,才能更新这里,不然只有7%,别问我怎么知道的
        //     dp[u][1] = max(dp[u][1], dp[u][0] - max(dp[i][0], dp[i][1]) + dp[i][0] + 2);
        // }
    }
    for (LL i : G[u]) { 
        if (i == f)continue;
        if(checksqrt(a[i]*a[u])){ 
            dp[u][1] = max(dp[u][1], dp[u][0] - max(dp[i][0], dp[i][1]) + dp[i][0] + 2);
        }
    }
}
int main() {
    LL n;
    cin >> n;
    for (LL i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (LL i = 1; i < n; i++) {
        LL u, v;  
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, -1);
    cout << max(dp[1][0], dp[1][1]) << "\n";
}
相关推荐
江畔柳前堤1 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore2 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考4 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX4 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面5 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号5 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽5 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI5 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者7 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者7 小时前
【征程6】校准量化中HistogramObserver解析
算法