【笔试】美团2024年春招第二场笔试(技术)

【笔试】美团2024年春招第二场笔试(技术)

文章目录

      • [T1 模拟](#T1 模拟)
      • [T2 模拟](#T2 模拟)
      • [T3 模拟,快速幂/打表](#T3 模拟,快速幂/打表)
      • [T4 众数、前缀和、树状数组](#T4 众数、前缀和、树状数组)
      • [T5 逆序对,树状数组](#T5 逆序对,树状数组)

T1 模拟

题目:数组求和,判断是否要减一个数

思路:模拟即可

cpp 复制代码
//T1
//AC
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

int main() {
    int n;  cin>>n;
    LL sum = 0;
    for(int i = 1; i <= n; i++){
        LL x;  cin>>x;
        sum += x;
    }
    LL a, b;  cin>>a>>b;
    sum = sum-a-b;
    cout<<sum<<"\n";
}

T2 模拟

题目:

  • 1、所有字母都是小写。例如:good
    2、所有字母都是大写。例如:APP
    3、第一个字母大写,后面所有字母都是小写。例如:Alice
  • 给个字符串最少几次能合法

思路:

  • 最多四种情况判断一下即可
cpp 复制代码
//T2
//AC
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

int main() {
    string s;  cin>>s;
    int sm = 0;
    for(int i = 0; i< s.size(); i++){
        if(islower(s[i])){
            sm++;
        }
    }
    int bg = s.size()-sm;
    int ans = min(bg, sm);
    if(isupper(s[0])){
        ans = min(ans, bg-1);
    }
    cout<<ans<<"\n";
}

T3 模拟,快速幂/打表

  • 题目:数组,每次操作将除了第 x 个元素的其余元素翻倍,操作q次,求最后的数组和。
  • 思路:先假设每个数每次都翻倍,维护每个数没有翻倍的次数,最后除回去就行。
cpp 复制代码
//T3
//AC
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
const LL mod = 1e9+7;
LL a[maxn], v[maxn];
LL pows[maxn];
int main() {
    pows[0] = 1;
    for(int i = 1; i < maxn; i++){
        pows[i] = pows[i-1]*2%mod;
    }
    int n, q;  cin>>n>>q;
    for(int i = 1; i <= n; i++){
        cin>>a[i];
    }
    LL fb = q;
    while(q--){
        int xi;  cin>>xi;
        v[xi]++;
    }
    LL ans = 0;
    for(int i = 1; i <= n; i++){
        ans = (ans + (pows[fb-v[i]]*a[i]%mod))%mod;
    }
    cout<<ans<<"\n";
}

T4 众数、前缀和、树状数组

题目:求数组的所有子数组的众数之和,众数有多个时取小的那个。

输入

3

2 1 2

输出

9

思路1:

  • 取值只有1和2,肯定要用起来。考虑对答案的贡献,默认所有区间+1,因为至少1嘛。然后最多也就是2,什么情况下会是2呢,对于区间和>区间长度*1.5的,也就是2的个数超过区间一半的时候。
  • 暴力所有区间n^2,然后前缀和O1区间和判断累加,到这能拿70%(其实也就是找2是众数的区间有多少个的情况)
cpp 复制代码
//T4-70%
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2e5+10;
LL a[maxn], s[maxn];
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    LL n;  cin>>n;
    LL ans = 0;
    for(LL i = 1; i <= n; i++){
        cin>>a[i];
        // a[i]--;
        // ans += a[i];
        s[i] = s[i-1]+a[i];
    }
    // for(LL l = 1; l <= n; l++){
    //     for(LL r = l; r <= n; r++){
    //         LL sum = s[r]-s[l-1];
    //         LL c2 = sum-(r-l+1);
    //         LL c1 = (r-l+1)-c2;
    //         // for(int k = l; k <= r; k++){
    //         //     if(a[k]==1)c1++;
    //         //     else c2++;
    //         // }
    //         if(c1>=c2)ans += 1;
    //         else ans += 2;
    //     }
    // }
    // 找出区间和比1.5倍区间长度要长的,+2(或者说加+1,然后加全部区间个数)
    ans = (1+n)*n/2;
    for(int len = 1; len <= n; len++){
        for(int i = 1; i+len<=n; i++){
            if((s[i+len-1]-s[i-1]) > len+len/2+len%2)ans++;
        }
    }
    cout<<ans<<"\n";
    // LL nn = (1+n)*n/2;
    // LL s1 = 0, s2 = 0;
    // for(int i = 1; i <= n; i++){
    //     LL x;  cin>>x;
    //     if(x==1)s1++;
    //     else s2++;
    // }
    // cout<<nn*s2/s1<<"\n";
}

思路2:

  • 考虑区间枚举怎么优化,考虑区间总个数一样,换成求1是众数的的区间有多少个。
  • 把1和2换成-1和1。数组的众数是 1 等价于数组的和不小于 0,此时只需要找出有多少个子数组的和不小于 0 (剩下的就是众数2)。 这里还是前缀和, 前面有几个前缀和 ≤ 当前的前缀和
  • 这里有点类似于求逆序对时候的做法,用下标为前缀和,权值为 1 的树状数组 统计某个取值范围内,有多少个前缀和。
cpp 复制代码
//T4-AC
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn = 2e5+10;
LL n, v[maxn*2+10];
void add(LL x, LL y){
    for(LL i = x; i <= 2*maxn; i += i&(-i)){ // n-> 2maxn
        v[i] += y;
    }
}
LL query(LL x){
    LL res = 0;
    for(LL i = x; i > 0; i -= i&(-i)){
        res += v[i];
    }
    return res;
}
int main() {
    cin>>n;
    LL t = 0, res = 0;
    add(maxn, 1LL);  //有负数,需要转换一下
    for(LL i = 1; i <= n; i++){
        LL x;  cin>>x;
        if(x==1LL)t++; else t--;
        res += query(t+maxn);
        // cout<<res<<"\n";
        add(t+maxn, 1LL);
    }
    LL cnt = n*(n+1)/2;
    // cout<<res<<"\n";
    cout<<res+2*(cnt-res)<<"\n";
}

T5 逆序对,树状数组

题目:给你一个排列,定义f(i)为a[i]取反后形成的数组的逆序对数量,求f(1)到f(n)的值。

思路:不难想到,先来个原先的逆序对。 然后扫一遍,过程中维护一下左右比当前数的大小关系,推导一下公式算一下即可。

cpp 复制代码
//T5
//AC
// = 逆序对-l大于ai-r小于ai+l全部
// = 逆序对+l小于ai-r小于ai
// 排列:ai-1 = l小于ai+r小于ai,维护左边比ai小的数的个数
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn = 200010;
struct node{ LL v, p; }a[maxn];
bool cmp(node x, node y){return x.v<y.v; }
LL n;
LL v[maxn], res[maxn];
void add(LL x, LL y){
    for(LL i = x; i <= n; i += i&(-i)){
        v[i] += y;
    }
}
LL query(LL x){
    LL res = 0;
    for(LL i = x; i > 0; i -= i&(-i)){
        res += v[i];
    }
    return res;
}
int main() {
    cin>>n;
    for(LL i = 1; i <= n; i++){
        cin>>a[i].v; a[i].p = i;
    }
    sort(a+1,a+n+1,cmp);
    LL ans = 0;
    for(LL i = n; i>= 1; i--){
        // cout<<a[i].v<<"\n";
        add(a[i].p,1);
        ans += query(a[i].p-1);
        LL lmax = query(a[i].p-1);
        LL lmin = a[i].p-1-lmax;
        LL rmin = a[i].v-1-lmin;
        res[a[i].p] = lmin-rmin;
    }
    // cout<<ans<<"\n";
    for(LL i = 1; i <= n; i++){
        cout<<ans+res[i]<<" ";
    }
}
// 64 位输出请用 prLLf("%lld")
相关推荐
浮生如梦_1 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错5 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny6 小时前
计算网络信号
java·算法·华为
景鹤6 小时前
【算法】递归+深搜:814.二叉树剪枝
算法
iiFrankie6 小时前
SCNU习题 总结与复习
算法
Dola_Pan7 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法