美团0316春招笔试题

下面是美团2024-03-16笔试真题,进行了VP,由于未参与评测,故不保证正确性,仅供参考。

第一题 小美点外卖

在这里插入图片描述

求和然后减去满减和红包即可。

#include <bits/stdc++.h>
using namespace std;
using LL = long long ;
int n, t, x, y;
LL ans;

int main() {
    scanf("%d", &n);
    while (n -- ) {
        scanf("%d", &t);
        ans += t;
    }
    scanf("%d%d", &x, &y);
    printf("%lld\n", ans - x - y);
}

第二题 小美的合法单词

在这里插入图片描述

考虑三种情况分别需要的操作次数,取最小值即可。

先扫描字符串s,并用变量big和small分别统计字符串s中大写字母、小写字母的个数。

然后还要处理第一个字符是大写的情况:

首先初始化变量t=s.size(),当第一个字符是大写字母时,执行t = t - 1 - small。减去1是因为去掉第一个大写字母,然后再减去small,这样得到的就是后面剩余的大写字符个数。

为什么是t-1-small而不是t-1-big呢?举个例子:s=“AaaBbCD”,此时big=4,small=3。

  • 若执行t-1-big,则此时t的结果就是2,那么答案为min{big, small, t} = 2,但显然答案应该是3(将后面的B,C,D修改为小写)。
  • 若执行t-1-small,则此时t的结果就是3,那么答案为min{big, small, t} = 3,这显然就是正确答案3(将后面的B,C,D修改为小写)。

说白了就是由于题目要求第一个字母大写,后面所有字母都是小写。t-1-small就是将后面统计除了首位这个大写字母外剩余部分的大写字母个数,而我们需要将这些大写字母个数就是我们需要修改为小写字母所需要的操作次数。

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

int main() {
    string s;
    cin >> s;
    int big = 0, small = 0, t = s.size();
    for (auto& c : s) {
        if (c >= 'A' && c <= 'Z')   ++ big;
        else if (c >= 'a' && c <= 'z')  ++ small;
    }
    if (s[0] >= 'A' && s[0] <= 'Z') t = t - 1 - small;
    printf("%d\n", min({small, big, t}));
}

第三题 翻倍元素

在这里插入图片描述

统计每个元素最后翻倍的次数即可。

如下表:

数组元素a[]翻倍次数times[]最终结果
a[1]=11 1 × 2 1 1\times 2^1 1×21
a[2]=21 2 × 2 1 2\times 2^1 2×21
a[3]=32 3 × 2 2 3\times 2^2 3×22
a[4]=42 4 × 2 2 4\times 2^2 4×22

因此最终结果为2、4、12、16,答案即为2+4+12+16=34。

对于快速求 a b a^b ab显然可以使用快速幂。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, MOD = 1e9 + 7;
int a[N], times[N], n, m;

int qmi(int a, int b) {
    int ans = 1;
    while (b) {
        if (b & 1)  ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ans % MOD;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++ i) {
        scanf("%d", &a[i]);
        times[i] = m;
    }
    for (int i = 1; i <= m; ++ i) {
        int x;
        scanf("%d", &x);
        -- times[x];
    }

    int ans = 0;
    for (int i = 1; i <= n; ++ i) {
        ans = (ans + a[i] * qmi(2, times[i]) % MOD) % MOD;
    }
    printf("%d\n", ans);
}

第四题 小美的众数

在这里插入图片描述

首先需要观察到元素 a i a_i ai只有1和2这两种取值。由于它的数值只有1和2,所以记录一个前缀和。如果说当前值是1就前缀和加1,如果说当前值是2,就前缀和减1。即我们定义数组 s i s_i si表示区间 [ 1 , i ] [1,i] [1,i]中元素1和元素2的被标记为+1和-1之后的前缀和。

对于一个前缀和 s i s_i si来说,它前面有多少个 s j s_j sj的值比 s i s_i si小,就说明,1的个数会大于等于2的个数,那么这些数量的区间,众数必然是元素1。 i i i减去这些区间的数量,也就是剩下的区间数量,众数就是2了。

对于如何求一个前缀和 s i s_i si来说,它前面有多少个 s j s_j sj的值比 s i s_i si小,这可以用树状数组来求解。

为什么要加偏移量OFFSET = n+1呢?

这是因为数组s[]取值有可能是负数(这是由于将元素1和元素2的被标记为+1和-1导致的),最坏情况下s[]取值可能是 − n -n n。但是我们知道树状数组下标是从1开始的,不能是<1的,故我们加上偏移量n+1,使得保证树状数组的下标是正确从1开始。

如何理解query(s[i] + OFFSET) + (i - query(s[i] + OFFSET)) * 2这个式子呢?

  • query(s[i] + OFFSET)其实完整写法是query(s[i] + OFFSET) * 1,它求解的是如果当前区间 [ 1 , i ] [1,i] [1,i]中的众数是元素1的话,那么就求这些子区间中众数1的总和。
  • (i - query(s[i] + OFFSET)) * 2,它求解的是如果当前区间 [ 1 , i ] [1,i] [1,i]中的众数是元素2的话,那么就求这些子区间中众数2的总和。当前有 i i i个元素,其中众数是元素1的个数有query(s[i] + OFFSET)个,那么众数是元素2的个数就为(i - query(s[i] + OFFSET))。然后求这些子区间中众数2的总和即可。
#include <bits/stdc++.h>
const int N = 2e5 + 10;
using LL = long long ;
int a[N], s[N], tr[N * 2], n;

inline int lowbit(int x) {
    return x & -x;
}

void modify(int x, int k) {
    for (int i = x; i <= 2 * n + 10; i += lowbit(i)) tr[i] += k;
}

LL query(int x) {
    LL ans = 0;
    for (int i = x; i; i -= lowbit(i)) ans += tr[i];
    return ans;
}

int main() {
    scanf("%d", &n);
    int OFFSET = n + 1;	// 偏移量,防止下标是负数,使得下标从1开始
    for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);

    modify(0 + OFFSET, 1);  // 边界初始化!!!

    LL ans = 0;
    for (int i = 1; i <= n; ++ i) {
        if (a[i] == 1)  s[i] += s[i - 1] + 1;
        else    s[i] += s[i - 1] - 1;
        // query(s[i] + OFFSET) * 1计算出如果1是众数时的和
        // (i - query(s[i] + OFFSET)) * 2计算出如果2是众数时的和
        ans += query(s[i] + OFFSET) + (i - query(s[i] + OFFSET)) * 2;
        modify(s[i] + OFFSET, 1);
    }
    printf("%lld", ans);
}

第五题 小美的逆序对

在这里插入图片描述

本题可以考虑使用树状数组来求逆序对。

我们可以先对原数组求一遍逆序对。对于第 i i i个数字,它在变为最小的数字后,在它之前的所有比它小的数字都会和它组成逆序对,在它之后所有比它小的数字会由原本构成逆序对转变成不构成逆序对。设在它左侧比它小的数字的个数为cnt,那么在它右侧比它小的数字的个数就是x - 1 - cnt。因此当元素x取反后,它左侧这cnt个数字就比x大,增加了cnt个逆序对,然后它右侧这x-1-cnt个数字就比x大,减少了x-1-cnt个逆序对。由此逆序对的增量就是x - (x - 1 - cnt)个。考虑原本的逆序对数目s,则第 i i i个数字取反后的逆序对数目为s + x - (x - 1 - cnt)

#include <bits/stdc++.h>
const int N = 2e5 + 10;
using LL = long long ;
int t[N], tr[N], n;

inline int lowbit(int x) {
    return x & -x;
}

void modify(int x, int k) {
    for (int i = x; i <= n; i += lowbit(i)) tr[i] += k;
}

LL query(int x) {
    LL ans = 0;
    for (int i = x; i; i -= lowbit(i)) ans += tr[i];
    return ans;
}

int main() {
    scanf("%d", &n);
    LL s = 0;
    for (int i = 1; i <= n; ++ i) {
        int x;
        scanf("%d", &x);
        s += query(n) - query(x);
        // cnt表示x左侧比x小的元素个数, x - 1 - cnt表示x右侧比x小的元素个数
        LL cnt = query(x - 1);
        t[i] = cnt - (x - 1 - cnt);
        modify(x, 1);
    }

    for (int i = 1; i <= n; ++ i) printf("%lld ", s + t[i]);
}

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符处理的问题。需要使用字符的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目三:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心菜不卷Iris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值