美团2024春招第一场笔试

美团2024春招第一场笔试

  1. 小美的平衡矩阵

小美拿到了一个 n ∗ n n * n nn 的矩阵,其中每个元素是 0 0 0 或者 1 1 1

小美好认为一个矩形区域是完美的,当且仅当该区域内 0 0 0 的数量恰好等于 1 1 1 的数量。

现在,小美希望你回答有多少个 i ∗ i i * i ii 的完美矩形区域。你需要回复 1 ≤ i ≤ n 1 \leq i \leq n 1in 的所有答案。

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 256M,其他语言512M

输入描述:
第一行输入一个正整数 n n n ,代表矩阵大小。
接下来的 n n n 行,每行输入一个长度为 n n n 01 01 01 串,用来表示矩阵。
1 ≤ n ≤ 200 1 \leq n \leq 200 1n200

输出描述:
输出 n n n 行,第 i i i 行输出 i ∗ i i * i ii 的完美矩形区域的数量。

示例1

输入例子:
4
1010
0101
1100
0011

输出例子:
0
7
0
1

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.nextLine();
        String[] s = new String[n + 1];
        for(int i = 1; i <= n; i ++ ){
            s[i] = in.nextLine();
        }
        int[][] a = new int[n + 1][n + 1];
        for(int i = 1; i <= n; i ++ ){
            for(int j = 1; j <= n; j ++ ){
                a[i][j] = s[i].charAt(j - 1) - '0';
                a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
            }
        }
        for(int w = 1; w <= n; w ++ ){
            if(w % 2 != 0){
                System.out.println(0);
                continue;
            }
            int ans = 0, tar = w * w;
            for(int i = 1; i <= n; i ++ ){
                int x2 = i - 1 + w;
                if(x2 > n) break;
                for(int j = 1; j <= n; j ++ ){
                    int y2 = j - 1 + w;
                    if(y2 > n) continue;
                    if(getSum(a, i, j, x2, y2) == tar / 2) ans ++;
                }
            }
            System.out.println(ans);
        }
        in.close();
    }
    public static int getSum(int[][] a, int x1, int y1, int x2, int y2){
        return a[x2][y2] - a[x1 - 1][y2] - a[x2][y1 - 1] + a[x1 - 1][y1 - 1];
    }
}
  1. 小美的数数组询间

小美拿到了一个由正整数组成的数组,但其中有一些元素是未知的(用 0 来表示)。
现在小美想知道,如果那些未知的元素在区间 [l, r] 范围内随机取值的话,数组所有元素之和的最小值和最大值分别是多少?
共有 q 次询问。

输入描述:

第一行输入两个正整数 n, q,代表数组大小和询问次数。
第二行输入 n 个整数 a[i],其中如果输入的 a[i] 为 0,则说明 a[i] 是未知的。
接下来的 q 行,每行输入两个正整数 l, r,代表一次询问。

1 <= n, q <= 10^5
0 <= a[i] <= 10^9
1 <= l <= r <= 10^9

输出描述:

输出 q 行,每行输出两个正整数,代表所有元素之和的最小值和最大值。

示例1

输入例子:

3 2
1 0 3
1 2
4 4

输出例子:

5 6
8 8

例子说明: 只有第二个元素是未知的。
第一次询问,数组最小的和是 1+1+3=5,最大的和是 1+2+3=6。
第二次询问,显然数组的元素必然是 8。

#include <iostream>
using namespace std;
typedef long long ll;
const int N = 1e5 + 6;
int a[N];
int main() {
    int n, q;
    cin >> n >> q;
    ll ans = 0, cnt = 0;
    for(int i = 0; i < n; i ++ ){
        cin >> a[i];
        ans += a[i];
        if(a[i] == 0) cnt ++;
    }
    while(q -- ){
        ll l, r;
        cin >> l >> r;
        cout << ans + l * cnt << " " << ans + r * cnt << "\n";
    }
}
// 64 位输出请用 printf("%lld")
  1. 小美的MT

MT是美团的缩写,因此小美很喜欢这两个字母。
现在小美拿到一个仅由大写字母组成的字符串,她可以最多操作k次,每次可以修改任意一个字符。小美想知道,操作结束后共有多多少’M’和’T’字符?

输入描述:
第一行输入两个正整数n,k,代表字符串长度和操作次数。
第二行输入一个长度为n的、仅由大写字母组成的字符串。
1≤k≤n≤10^5

输出描述:
输出操作结束后共有多少个’M’和’T’字符。

示例1

输入例子:
5 2
MTUAN

输出例子: 4
修改第三个和第五个字符,形成的字符串为 MTTAM,这样共有 4 个 ‘M’ 和 ‘T’。

#include <iostream>
#include <cstring>
using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    string s;
    cin >> s;
    int ans = 0;
    for(auto x : s){
        if(x == 'M' || x == 'T'){
            ans ++;
        }else{
            if((-- k) >= 0) ans ++;
        }
    }   
    cout << ans; 
}
// 64 位输出请用 printf("%lld")
  1. 小美的朋友关系

小美认为,在人际交往中,但是随着时间的流逝,朋友的关系也是会慢慢淡忘的,最终朋友关系就淡忘了。

现在初始有一些朋友关系,存在一些事件会导致两个人淡忘了他们的朋友关系。小美想知道某一时刻中,某两人是否可以通过朋友介绍互相认识?

事件共有2种:

1 uv:代表编号u的人和编号v的人淡忘了他们的朋友关系。
2 uv:代表小美查询编号u的人和编号v的人是否能通过朋友介绍互相认识。

注:介绍可以有多层。比如2号把1号介绍给3号,然后3号再把1号介绍给4号,这样1号和4号就认识了。

输入描述:

第一行输入三个正整数n,m,q,代表总人数,初始的朋友关系数量,发生的事件数量。
接下来的m行,每行输入两个正整数u,v,代表初始编号u的人和编号v的人是朋友关系。
接下来的q行,每行输入三个正整数op,u,v,含义如题目描述所述。

1 ≤ n ≤ 10^9
1 ≤ m, q ≤ 10^5
1 ≤ u, v ≤ n
1 ≤ op ≤ 2

保证至少存在一次查询操作。

输出描述:

对于每次2号操作,输出一行字符串代表查询的答案。如果编号u的人和编号v的人能通过朋友介绍互相认识,则输出"Yes"。否则输出"No"。

示例1

输入例子:

5 3 5
1 2
2 3
4 5
1 1 5
2 1 3
2 1 4
1 1 2
2 1 3

输出例子:

Yes
No
No

例子说明:

第一次事件,1号和5本来就是朋友,所以无事发生。
第二次事件是查询,1号和3号可以通过2号的介绍认识。
第三次事件是查询,显然1号和4号无法互相认识。
第四次事件,1号和2号淡忘了。
第五次事件,此时1号无法再经过2号和3号互相认识了。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 6;
// 离散化
map<int, int> mp;
int idx = 0;
int get(int x){
    return mp[x] == 0 ? mp[x] = ++ idx : mp[x];
}
// 未淡化前的朋友集合,淡化后的朋友集合
set<pair<int, int>> alls, thens;
// 并查集
int f[N * 2];
// 结果,操作
bool r[N];
int ops[N][3];
// 查询
int find(int x){
    return f[x] == x ? x : f[x] = find(f[x]);
}
// 合并
void merge(int x, int y){
    int fx = find(x), fy = find(y);
    f[fx] = fy;
}
int main() {
    int n, m, q;
    cin >> n >> m >> q;
    while(m -- ){
        int a, b;
        cin >> a >> b;
        a = get(a), b = get(b);
        if(a > b) swap(a, b);
        f[a] = a, f[b] = b;
        alls.insert({a, b}), thens.insert({a, b});
    }
    for(int i = 0; i < q; i ++ ){
        int a, b, c;
        cin >> a >> b >> c;
        ops[i][0] = a, b = get(b), c = get(c);
        if(b > c) swap(b, c);
        ops[i][1] = b, ops[i][2] = c;
        f[b] = b, f[c] = c;
        if(a == 1) thens.erase({ops[i][1], ops[i][2]});
    }
    for(auto& [a, b] : thens){
        merge(a, b);
    }
    for(int i = q - 1; i >= 0; i -- ){
        auto[a, b, c] = ops[i];
        if(a == 2) r[i] = find(b) == find(c);
        else{
            if(alls.find({b, c}) != alls.end()) merge(b, c);
        }
    }
    for(int i = 0; i < q; i ++ ){
        if(ops[i][0] == 2) 
            r[i] == true ? puts("Yes") : puts("No");
        
    }

}
// 64 位输出请用 printf("%lld")

5.小美的区间删除

小美拿到了一个大小为n的数组,她希望删除一个区间后,使得剩余所有元素的乘积末尾至少有k个0。小美想知道,一共有多少种不同的删除方案?

输入描述:
第二行输入两个正整数n,k。
第三行输入n个正整数a_i,代表小美拿到的数组。

1 ≤ n, k ≤ 10^5
1 ≤ a_i ≤ 10^9

输出描述:
一个整数,代表删除的方案数。

示例1

输入例子:

5 2
2 5 3 4 20

输出例子: 4
第一个方案,删除[3]。
第二个方案,删除[4]。
第三个方案,删除[3,4]。
第四个方案,删除[2]。

#include <iostream>
using namespace std;
const int N = 1e5 + 6;
int two[N], five[N];
long long ans;
int count(int x, int r){
    int t = 0;
    while(x % r == 0){
        t ++;
        x /= r;
    }
    return t;
}
int main() {
    int n, k;
    cin >> n >> k;
    for(int i = 1; i <= n; i ++ ){
        int x;
        cin >> x;
        two[i] = two[i - 1] + count(x, 2);
        five[i] = five[i - 1] + count(x, 5);
    }
    int s2 = two[n], s5 = five[n];
    for(int l = 1; l <= n; l ++ ){
        int r = n;
        int t2 = s2 - two[r] + two[l - 1];
        int t5 = s5 - five[r] + five[l - 1];
        while(l <= r && (t2 < k || t5 < k)){
            t2 += two[r] - two[r - 1];
            t5 += five[r] - five[r - 1]; 
            r --;
        }
        ans += r - l + 1;
    }
    cout << ans;
}
// 64 位输出请用 printf("%lld")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值