3.9 美团笔试

24年第一次笔试...

T1, 模拟

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

int main() {
    int n, k; cin >> n >> k;
    string s; cin >> s;
    int current = 0;
    for (auto c : s) {
        if (c == 'M' || c == 'T') current++;
    }
    int res = min(int(s.length()), current+k);
    cout << res << endl;
    return 0;
}

T2,模拟

注意数据范围,使用long

#include<bits/stdc++.h>

using namespace std;

int main() {
    int n, q; cin >> n >> q;
    long tmp, zeroCnt = 0, nonZeroSum = 0;
    for (int i = 0; i < n; i++) {
        cin >> tmp;
        if (tmp == 0) {
            zeroCnt++;
        } else {
            nonZeroSum += tmp;
        }
    }
    while (q--) {
        long l, r;
        cin >> l >> r;
        cout << nonZeroSum + zeroCnt*l << ' ' << nonZeroSum+zeroCnt*r << endl;
    }
    return 0;
}

T3,二维前缀和

#include<bits/stdc++.h>

using namespace std;

int main() {
    int n; cin >> n;
    vector<string> mat(n);
    for (int i = 0; i < n; i++) cin >> mat[i];
    int pre[205][205]{};
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            pre[i+1][j+1] =  pre[i+1][j] + pre[i][j+1] - pre[i][j] + (mat[i][j]=='1');
        }
    }
    for (int len = 1; len <= n; len++) {
        if (len % 2 == 1) {
            cout << 0 << endl;
            continue;
        }
        int current = 0, target = len*len/2;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int endI = i+len-1,  endJ =j+len-1;
                if (endI > n-1 || endJ > n-1) continue;
                int val = pre[endI+1][endJ+1] - pre[endI+1][j] - pre[i][endJ+1] + pre[i][j];
                if (val == target) current++;
            }
        }
        cout << current << endl;
    }
    return 0;
}

T4,前缀和 + 滑动窗口

(注意数据范围, 使用long)

思路:

  • 给出的数字都是不为0的,最终乘积的0 一定是由素因子 2, 5构成的, 因此主要关心区间内2、5的数量
  • 要求删除区间后0的数量应该大于等于k,即删除区间后剩下的数中 素因子2、5的数量必须同时大于等于k

滑动窗口: 枚举以i开始的可以删除的子串数量,for循环内部while结束后, i-j对应的子串是不符合条件的,但i到 [i+1、i+2、 ... j-1]都是满足条件的。

复杂度 O(n)

#include<bits/stdc++.h>

using namespace std;

const int MaxN = 1e5+5;
int main() {
    int n, k; cin >> n >> k;
    int arr[n];
    long pre2[MaxN]{}, pre5[MaxN]{};
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
        int cntFactor2 = 0, cntFactor5 = 0;
        for (int x = arr[i]; x % 2 == 0; x /= 2) cntFactor2++;
        for (int x = arr[i]; x % 5 == 0; x /= 5) cntFactor5++;
        pre2[i+1] += pre2[i] + cntFactor2;
        pre5[i+1] += pre5[i] + cntFactor5;
    }

    long res = 0, zeroCnt = min(pre2[n], pre5[n]);
    for (int i = 0, j = 0; i < n; i++) {
        while (j < n) {
            int range2 = pre2[j+1] - pre2[i];
            int range5 = pre5[j+1] - pre5[i];
            int remain2 = pre2[n] - range2;
            int remain5 = pre5[n] - range5;
            if (min(remain2, remain5) < k) break;
            j++;
        }
        res += max(j-i, 0);
    }
    cout << res << endl;
    return 0;
}

T5, 并查集、离散化、逆向思维

笔试时想到了并查集,但没写出来,写了个dfs,超时~

笔试后参考@Y丶bs大佬的思路使用并查集实现了下。 ref: https://www.nowcoder.com/discuss/596124837462978560

并查集写法

#include <bits/stdc++.h>

using namespace std;
const int MaxN = 4e5+5;
int fa[MaxN];

int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void merge(int x, int y) {
    int faX = find(x);
    int faY = find(y);
    if (faX != faY) {
        fa[faX] = faY;
    }
}

int main() {
    iota(fa, fa+MaxN, 0);   // 初始化fa数组
    unordered_set<int> points;  // 记录所有点, 离散化使用
    int n, m, q; cin >> n >> m >> q;
    vector<vector<int>> edges;
    for (int i = 0; i < m; i++) {
        int a, b;  cin >> a >> b;

        points.insert(a);
        points.insert(b);
        edges.push_back({a, b});
    }

    unordered_map<int, unordered_set<int>> delEdgeMap;
    vector<vector<int>> ops; 
    while (q--) {
        int op, u, v; cin >> op >> u >> v;

        points.insert(u);
        points.insert(v);
        ops.push_back({op, u, v});
        if (op == 1) {
            delEdgeMap[u].insert(v);
            delEdgeMap[v].insert(u);
        } 
    }

    int idx = 0;    // 离散化初始idx
    unordered_map<int, int> val2Idx;
    for (auto u : points) val2Idx[u] = idx++;

    // 建立并查集、不使用删除的边
    for (auto &e : edges) {
        int u = e[0], v = e[1]; 
        if (delEdgeMap.count(u) && delEdgeMap[u].count(v)) {
            continue;
        }

        merge(val2Idx[u], val2Idx[v]);
    }

    vector<bool> result;
    reverse(ops.begin(), ops.end());  // 反向遍历
    for (auto &item : ops) {
        int op = item[0], u = item[1], v = item[2];
        int idxU = val2Idx[u], idxV = val2Idx[v];
        if (op == 1) {  // 加边操作
            merge(idxU, idxV);
            continue;
        }

        if (find(idxU) == find(idxV)) {
            result.push_back(true);
        } else {
            result.push_back(false);
        }
    }
    for (int i = result.size()-1; i >= 0; i--) {
        if (result[i]) {
            printf("Yes\n");
        } else {
            printf("No\n");
        }
    }

    return 0;
}

暴力dfs解法(超时...)

#include <bits/stdc++.h>

using namespace std;
int n, m, q;
unordered_map<int, unordered_map<int, bool>> g;

bool dfs(int u, int parent, int target) {
    if (u == target) {
        return true;
    }
    for (auto &[v, ok] : g[u]) {
        if (v != parent && ok && dfs(v, u, target)){
            return true;
        }
    }
    return false;
}

int main() {
    cin >> n >> m >> q;
    for (int i = 0; i < m; i++) {
        int a, b; cin >> a >> b;
        g[a][b] = true;
        g[b][a] = true;
    }
    while (q--) {
        int op, u, v;
        cin >> op >> u >> v;
        if (op == 1) {
            g[u][v] = false;
            g[v][u] = false;
            continue;
        } 
        if (dfs(u, -1, v)) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
    return 0;
}
#美团2025实习生笔试##实习#
全部评论
倒序并查集
5 回复 分享
发布于 03-09 15:02 重庆
dfs是不是只能过百分之十
4 回复 分享
发布于 03-09 14:58 广东
想请教下第四题的思路,为什么加j-i就可以了呢?我有类似的想法,但是一直在纠结怎么算可删掉的数量,因为可以连着删,如果用n * (n + 1) / 2去算一个长度为n的子串的可删方法数,之后在移动i的时候就会重复删。
2 回复 分享
发布于 03-09 16:48 江苏
大佬,你给的并查集的代码过不了吧
1 回复 分享
发布于 03-12 13:37 北京
我第二题写的跟你基本上一个思路,就是只a了16,也不知道是哪个测试用例不行,看了半天也不知道是哪里出问题
点赞 回复 分享
发布于 03-09 15:37 福建
第三题一模一样的思路,用python写超时了,只过了50,磕了太多时间在上边了
点赞 回复 分享
发布于 03-09 15:43 新加坡
还有第四题乘积为0的就不是有三种情况2*5,4*5,5*6吗?为什么乘积为0就一定是2跟5相乘呢?
点赞 回复 分享
发布于 03-09 18:10 福建
笔试是什么形式啊 和牛客上的题一样吗 显示错误用例或者是别的么 还是就显示百分比
点赞 回复 分享
发布于 03-12 16:03 吉林
笔试可以用自己本地的ide吗
点赞 回复 分享
发布于 03-15 21:14 北京
请问一下,就五道编程题嘛?有其它的题型嘛?QAQ
点赞 回复 分享
发布于 03-16 01:09 广西
可以请教一下楼主第五题离散化的作用是什么嘛?
点赞 回复 分享
发布于 03-16 15:59 浙江
朋友关系是一步一步操作淡忘的,这里逻辑先把所有淡忘关系都处理了,然后才建立并查集去查找关系,是不是会丢失关系淡忘前的询问操作?
点赞 回复 分享
发布于 05-03 15:35 北京

相关推荐

挣K存W养DOG:他真的很中意你,为什么不回他
点赞 评论 收藏
分享
ArisRobert:统一解释一下,第4点的意思是,公司按需通知员工,没被通知到的员工是没法去上班的,所以只要没被通知到,就自动离职。就是一种比较抽象的裁员。
点赞 评论 收藏
分享
48 151 评论
分享
牛客网
牛客企业服务