【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】

题目一:

【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第1张图片
【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第2张图片

解题思路:

水题略。

代码一:

#include 
#include 
#include 
using namespace std;

int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        int n, X;
        cin >> n >> X;
        int a;
        int suma = 0; // 总学分
        int b;
        for(int i = 0; i < n; i++)
        {
            cin >> a;
            suma += a;
        }
        bool flag = true;
        double sum = 0; // 成绩学分加权和
        for(int i = 0; i < n; i++)
        {
            cin >> b;
            sum += (((double)b * (double)a) / (double)suma);
            if(b < 60)
            {
                flag = false; // 有不及格的课
                break;
            }
        }
        if(flag == false) cout << "NO" << endl;
        else
        {
            if(sum >= X) cout << "YES" << endl;
            else cout << "NO" << endl;
        }
    }
    return 0;
}

题目二:

【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第3张图片
【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第4张图片

解题思路:

题目要求所有给出的数可以两两组成一对和相等(target)的面,没有一个数是多余的。那么一定符合一个最小的数加一个最大的数正好等于target,一个次小的数加一个次大的数正好等于target……的规律。
所以方案是先给 n 个数排序,两端同步向内遍历,判断两数之和是否相等。

代码二:

#include 
#include 
#include 

using namespace std;

bool canMakeDice(int n, vector<int>& nums) {
    sort(nums.begin(), nums.end()); // 将数字从小到大排序
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += nums[i];
    }
    int target = sum / (n/2);
    int left = 0, right = n-1;
    while (left < right) { // 从两端向中间遍历,如果两端数字之和不等于 target,说明不能构成骰子
        if (nums[left] + nums[right] != target) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> nums(n);
        for (int i = 0; i < n; i++) {
            cin >> nums[i];
        }
        if (canMakeDice(n, nums)) {
            cout << "YES" << endl;
        } else {
            cout << "NO" << endl;
        }
    }
    return 0;
}

题目三:

【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第5张图片
【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第6张图片

解题思路:

贪心。将每种作物的性价比排序,性价比相同的话将需要时间较少的作物放在前面。然后从性价比高的作物开始,计算最多可以种多少这种作物以获得更多收益(注意,题目说了可以重复购买一种作物的种子),当剩余天数不满足需要的天数时,按性价比顺序找下一种剩余时间还可以种的作物,直到将所有作物遍历完。

代码三:

#include 
#include 
#include 

using namespace std;

struct Node { // 作物
    double rate; // 性价比(收益/时间)
    int needDay; // 需要的时间
    int money; // 收益(卖出价格-买入价格)
};

bool cmp(Node a, Node b) { // 给每种作物的性价比排序,性价比相同的话将需要时间较少的作物放在前面
    if (a.rate == b.rate) {
        return a.needDay < b.needDay;
    }
    return a.rate > b.rate;
}

int main(){
    int n, m;
    cin >> n >> m;
    vector<Node> v; // 作物
    int t[2005], a[2005], b[2005];
    for (int i = 0; i < n; i++) {
        cin >> t[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }
    for (int i = 0; i < n; i++) {
        Node node;
        node.money = b[i] - a[i];
        node.rate = (double)node.money / (double)t[i];
        node.needDay = t[i];
        v.push_back(node);
    }
    sort(v.begin(), v.end(), cmp); // 给作物性价比排序
    int maxMoney = 0; // 最大收益
    int nowDay = 0; // 当前所用时间
    int index = 0; // 当前作物的下标
    while (index < n && nowDay < m) {
        if (nowDay + v[index].needDay <= m) { // 只要当前时间加上这种作物需要的时间不超过总时间,就尽可能多地买排在前面的性价比高的作物
            maxMoney += v[index].money;
            nowDay += v[index].needDay;
        } else {
            index++;
        }
    }
    cout << maxMoney << endl;
    return 0;
}

题目四:

【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第7张图片
【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第8张图片

解题思路:

前(后)缀数组。
先计算后缀和数组 suf,suf[i] 表示删掉从 i 到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价;
然后计算最小代价后缀数组 minsuf,minsuf[i] 表示删掉从 i 或之后任意位置到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价的最小值;
最后遍历所有可能删掉的前缀,加上对应的最小代价后缀,比较选取总代价的最小值。

代码四:

#include 
#include 
#include 
using namespace std;

int main()
{
    string s;
    cin >> s;
    int n = s.size();
    vector<int> suf(n + 1, 0); // suf[i]后缀和数组:表示删掉从 i 到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价
    int sum1 = 0, sum0 = 0;
    for(int i = 0; i < n; i++)
    {
        sum1 += s[i] - '0'; // 整个字符串1的个数
    }
    sum0 = n - sum1; // 整个字符串0的个数
    suf[n] = sum0;
    for(int i = n - 1, sum00 = sum0, sum11 = sum1; i >= 0; i--)
    {
        if(s[i] == '1') {
            suf[i] = suf[i + 1] + 1;
            sum1--;
        }
        else {
            suf[i] = suf[i + 1] - 1;
        }
    }
    vector<int> minsuf(n + 1, 100000); // minsuf[i]表示删掉从 i 或之后任意位置到字符串末尾的后缀,并保留字符串剩余部分所需的操作代价的最小值
    int minn = 100000;
    for(int i = n - 1; i >= 0; i--)
    {
        minn = min(minn, suf[i]);
        minsuf[i] = minn;
    }
    int ans = 100000;
    for(int i = 0, temp = 0; i < n; i++)
    {
        ans = min(ans, temp + minsuf[i]); // temp表示删掉 i-1 及其之前的前缀,并保留字符串剩余部分所需的操作代价;用temp加上i之后的最小后缀和,就是删掉当前前缀和最小代价后缀的总代价;遍历所有前缀的情况,ans取最小值
        if(s[i] == '1') temp++;
        else temp--;
    }
    cout << ans << endl;
    return 0;
}

题目五:

【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第9张图片
【2023-4-22 美团春招笔试题 开发岗(技术综合-后端&数开&软开)】_第10张图片

解题思路:

分治法。
递归将参赛者不断两两分组,直到分到一人一组,将小组的胜者层层返回,上层的小组再将两胜者比较。

代码五:

#include 
#include 
#include 
#include 
using namespace std;

int winner(vector<vector<int>> &v, int begin, int end)
{
    if(begin == end) return begin; // 只有一个人,返回他的编号
    int a = winner(v, begin, (begin + end) / 2); // 前半段比赛
    int b = winner(v, (begin + end) / 2 + 1, end); // 后半段比赛
    return v[a][b]; // a 和 b 比赛,a 胜利返回 a,b 胜利返回 b
}

int main()
{
    int k;
    cin >> k;
    int n = pow(2, k);
    vector<vector<int>> v(n + 1, vector<int>(n + 1, 0));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            cin >> v[i][j];
        }
    }
    cout << winner(v, 1, n) << endl;
    return 0;
}

你可能感兴趣的:(刷题,c++,算法,数据结构,求职招聘)