美团2025年春招第一场笔试【技术方向】个人题解

题目:10 道单选 + 3 道算法题

结果:只做出前两道题,第三题暴力0分

题图在网上找的

第一题:字符串解密

按规则模拟即可,为了防止可能出现的问题我取了下模,按理来说 p 每次乘法都可能溢出的,但是貌似没有设置这种坑

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

int main() {
    int T;
    cin >> T;
    while(T--){
        string s;
        cin >> s;
        string t;
        int p = 0;
        for(auto c : s){
            if(isalpha(c)){
                int len = t.size();
                if(len){
                    p %= len;
                    t = t.substr(p, len - p) + t.substr(0, p);
                }
                if(c == 'R') reverse(t.begin(), t.end());
                else t += c;
                p = 0;
            }else{
                p = p * 10 + c - '0';
            }
        }
        cout << t << endl;
    }
    return 0;
}

第二题:小美架炮

我的做法是排序一下,把相同横坐标或者纵坐标的点一块计算。

以相同横坐标为例,假设有5个点 a, b, c, d, e 横坐标相同,纵坐标递增,则 a,b,d,e 都能打到 1 个炮,c 能打到 2 个炮

纵坐标同理这样统计答案即可

复杂度还是排序的 O(nlogn) 吧

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 4;
struct node{
    int x, y, id;
};

int ans[N];
vector<node>a; 
int main() {
    int n;
    cin >> n;
    for(int x, y, i = 1;i <= n;i++){
        cin >> x >> y;
        a.push_back({x, y, i}); // 记录答案 id
    }
	// 按横坐标排序,相同横坐标一块计算往纵坐标方向打的数量
    sort(a.begin(), a.end(), [](const node& u, const node& v)->bool{
        return u.x == v.x ? u.y < v.y : u.x < v.x;
    });

    for(int i = 0;i < n;i++){
        int j = i;
        while(j < n && a[i].x == a[j].x) j++;
        j--;
		// [i, j] 区间内横坐标相等
        for(int k = i;k <= j;k++){
            if(k - 2 >= i) ans[a[k].id]++; // 往下打
            if(k + 2 <= j) ans[a[k].id]++; // 往上打
        }
        i = j;
    }

	// 同理的,按纵坐标排序
    sort(a.begin(), a.end(), [](const node& u, const node& v)->bool{
        return u.y == v.y ? u.x < v.x : u.y < v.y;
    });

    for(int i = 0;i < n;i++){
        int j = i;
        while(j < n && a[i].y == a[j].y) j++;
        j--;
        for(int k = i;k <= j;k++){
            if(k - 2 >= i) ans[a[k].id]++;
            if(k + 2 <= j) ans[a[k].id]++;
        }
        i = j;
    }

    for(int i = 1;i <= n;i++)
        cout << ans[i] << endl;
    return 0;
}

第三题:有根树

当场感觉是 LCA 最近公共祖先,但是忘记了板子,就想着暴力能得多少是多少吧,结果通过 0%

看了其他大佬的简略题解,自己写了下代码,可以通过样例,不知道能过吗。。。如果题目开放了测一下看看

前置知识:倍增,最近公共祖先

时间复杂度 O(nlogn)

假设 u,v 的最近公共祖先是 x,u 到 x 的 B U G 覆盖状态分别映射为 1 2 4(代码中的 bug 数组)

v 到 x 的 B U G 覆盖状态分别映射为 4 2 1 (代码中的 gub 数组)

比较难处理的是 B U G 的顺序问题,这里我也不确定对不对,有大佬的话可以指正,只做过 LCA 板子题,倍增的时候带状态的也是第一次做。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 6;
vector<int> a[N];
int n, m, d[N], fa[N][20], lg2[N], bug[N][20], gub[N][20];
char s[N];
int ok;

// y 比 x 离根近
int update(int x, int y){
	int ans = x;
	if((y & 1))
		ans |= 1;
	// 左边是先有 B 才填 U,右边是先有 G 才填 U
	if((y & 2) && (ans & 1))
		ans |= 2;
	if((y & 4) && (ans & 2))
		ans |= 4;
	return ans;	
}

void dfs(int now, int f) {
    d[now] = d[f] + 1;
    fa[now][0] = f;
	bug[now][0] |=  (s[now] == 'B');        // B -> 1
	bug[now][0] |= ((s[now] == 'U') << 1);  // U -> 2
	bug[now][0] |= ((s[now] == 'G') << 2);  // G -> 4
	gub[now][0] |=  (s[now] == 'G');
	gub[now][0] |= ((s[now] == 'U') << 1);
	gub[now][0] |= ((s[now] == 'B') << 2);
    int range = lg2[d[now]];
    for(int i = 1;i <= range;i++) {
		fa[now][i] = fa[fa[now][i - 1]][i - 1];
		bug[now][i] = update(bug[now][i - 1], bug[fa[now][i - 1]][i - 1]);	
		gub[now][i] = update(gub[now][i - 1], gub[fa[now][i - 1]][i - 1]);		
	}
    for(auto nxt : a[now]) 
		dfs(nxt, now);
}

int LCA(int x, int y) {
	int lok = 0, rok = 0;
    while (d[x] > d[y]) {
		lok = update(lok, bug[x][lg2[d[x] - d[y]]]);
		x = fa[x][lg2[d[x] - d[y]]];
	}
	while (d[y] > d[x]) {
		rok = update(rok, gub[y][lg2[d[y] - d[x]]]);
		y = fa[y][lg2[d[y] - d[x]]];
	}
	lok = update(lok, bug[x][0]);
	rok = update(rok, gub[y][0]);
    if (x == y){
		// 左边 BUG 或者 右边 GUB,或者 左边 B 和 右边 UG ...
		if(lok == 7 || rok == 7 || (lok == 1 && rok == 3) || (lok == 3 && rok == 1) || (lok == 3 && rok == 3))
    		return 1;
		else return 0;		
	}
    for (int i = lg2[d[x]]; i >= 0; i--) {
        if (fa[x][i] != fa[y][i]){
			lok = update(lok, bug[x][i]); 
			rok = update(rok, gub[x][i]); 
			x = fa[x][i], y = fa[y][i];
		}
    }
	lok = update(lok, bug[x][0]); 
	rok = update(rok, gub[x][0]); 
	lok = update(lok, bug[fa[x][0]][0]);
	if(lok == 7 || rok == 7 || (lok == 1 && rok == 3) || (lok == 3 && rok == 1) || (lok == 3 && rok == 3))
    	return 1;
	else return 0;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 2; i <= n; i++)
        lg2[i] = lg2[i - 1] + ((1 << (lg2[i - 1] + 1)) == i);
    for (int i = 1, fa; i <= n; i++) {
        scanf("%d", &fa);
        a[fa].push_back(i);
    }
	scanf("%s", s + 1);
    dfs(1, 0);
    while (m--) {
		int x, y;
        scanf("%d%d", &x, &y);
		ok = LCA(x, y);
        if(ok) cout << "NO" << endl;
		else cout << "YES" << endl;
    }
    return 0;
}
/*
5 3
0 1 1 2 2
AUGBC
4 3
4 5
4 1

9 3
0 1 1 2 2 3 3 4 8
CDBUGGCGB
7 8
8 6
9 6
*/
全部评论
最后一个不可以维护到根节点的路径做吗,反转一下拼在一起,然后O(n)判断一个字符串有没有子序列bug
点赞 回复 分享
发布于 昨天 11:52 北京
大佬,你这个有真题的是哪个网站
点赞 回复 分享
发布于 昨天 12:11 陕西
mark一下代码
点赞 回复 分享
发布于 昨天 17:26 安徽
Mark
点赞 回复 分享
发布于 昨天 22:37 新疆

相关推荐

03-08 20:45
郑州大学 Java
二仙桥混沌手锤大魔:6.米哈游干完本来就有点玉玉,7.做美团,嘻嘻我玩nm
投递美团等公司10个岗位
点赞 评论 收藏
分享
大佬们考的怎么样?看样子不能只刷acm编程题了,机器学习题也要刷下。😭
牛客561236133号:绷不住了,皮什么玩意来着
投递美团等公司10个岗位 >
点赞 评论 收藏
分享
评论
6
18
分享

创作者周榜

更多
牛客网
牛客企业服务