美团2024年秋招第一场笔试【算法】个人题解

在牛客刷到了,随便看下哈,部分题可能有更优做法(懒得想了 or 想不出来)。

小美的因子查询

小美对偶数因子很感兴趣,她将进行  次询问,每次都会给出一个正整数  ,请你告诉她  是否存在至少一个偶数因子。也就是说  是否存在某个因子是偶数。

题解:判断 是否为偶数即可,单组查询复杂度

#include<bits/stdc++.h>

using namespace std;
using i64 = long long;
#define endl '\n'

constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

void solve() {
    int n;
    cin >> n;

    cout << ((~n & 1) ? "YES" : "NO") << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 

    int t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

小美的密码

小美准备登录美团,需要输入密码,小美忘记了密码,只记得密码可能是 个字符串中的一个。小美会按照密码的长度从小到大依次尝试每个字符串,对于相同长度的字符串,小美随机尝试,并且相同的密码只会尝试一次。小美想知道,她最少需要尝试多少次才能登录成功,最多需要尝试多少次才能登录成功。小美不会重新尝试已经尝试过的字符串。成功登录后会立即停止尝试。

题解:暴力统计每种长度的字符串有多少,然后累加即可,注意去重。复杂度

#include<bits/stdc++.h>

using namespace std;
using i64 = long long;
#define endl '\n'

constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

void solve() {
    int n;
    cin >> n;

    string s;
    cin >> s;

    vector<int> len(1005, 0);
    map<string, bool> mp;
    while (n--) {
        string a;
        cin >> a;
        if (mp.count(a)) {
            continue;
        }
        len[a.size()]++;
        mp[a] = true;
    }

    int x = 0, y = 0;
    for (int i = 1; i < s.size(); i++) {
        x += len[i];
        y += len[i];
    }
    x++;
    y += len[s.size()];

    cout << x << " " << y << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 

    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

小美的数组删除

小美有一个长度为 的数组 ,他可以对数组进行如下操作:

● 删除第一个元素 ,同时数组的长度减一,花费为

● 删除整个数组,花费为

小美想知道将 数组全部清空的最小代价是多少,请你帮帮他吧。

题解:问题在于求解区间 ,这个东西做法很多,我用的是可持久化线段树,建树后暴力枚举即可。单组复杂度

#include<bits/stdc++.h>

using namespace std;
using i64 = long long;
#define endl '\n'

constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

constexpr int N = 2e5 + 5;
int tot = 0;
struct node {
    int ls, rs;
    int v;
} seg[N * 24];
int rt[N], a[N];
void pushup(int k) {
    seg[k].v = min(seg[seg[k].ls].v, seg[seg[k].rs].v);
}

int modify(int old, int l, int r, int pos, int v) {
    int p = ++tot;
    seg[p] = seg[old];
    if (l == r) {
        seg[p].v = v;
        return p;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) {
        seg[p].ls = modify(seg[old].ls, l, mid, pos, v);
    } else {
        seg[p].rs = modify(seg[old].rs, mid + 1, r, pos, v);
    }
    pushup(p);
    return p;
}

int query(int p, int l, int r, int pos) {
    if (l == r) {
        return l;
    }
    int mid = (l + r) >> 1;
    if (seg[seg[p].ls].v < pos) {
        return query(seg[p].ls, l, mid, pos);
    } else {
        return query(seg[p].rs, mid + 1, r, pos);
    }
}

void solve() {
    int n;
    i64 k, x;
    cin >> n >> k >> x;

    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        rt[i] = modify(rt[i - 1], 0, n, a[i], i);
    }

    i64 ans = 1LL * query(rt[n], 0, n, 1) * k;

    for (int i = 2; i <= n; i++) {
        i64 cur = 1LL * (i - 1) * x;
        cur += 1LL * query(rt[n], 0, n, i) * k;
        ans = min(ans, cur);
    }

    i64 cur = 1LL * n * x;
    ans = min(ans, cur);

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 

    int t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

小美和大富翁

小美在玩《大富翁》游戏,游戏中有 个城市排成一排,编号从 , 第 个城市上有一个数字 , 表示到达第 个城市可以获得 枚金币。

每一轮开始时小美会获得四张卡牌,分别可以跳跃 个城市,例如小美可以从城市 跳跃 个城市到达城市 。当小美使用完这 张卡牌后,会开启新的一轮。

初始时,小美拥有 枚金币,在任意时刻,小美的金币数量都必须大于等于 , 小美想知道她从第 个城市出发,到达第 个城市最多可以获得多少枚金币。

题解:这题显然是个 ,由于跳跃的方式一共只有四种,考虑状态压缩,将跳跃方式用四位二进制表示,该位为 表示已经使用过对应的卡牌。设 表示跳到第 个点时,使用卡牌的情况为 时可以获得的最多的金币数量。对应的转移是比较简单的,分为两种情况:之前未使用过这张卡牌,或者已经使用了所有卡牌并开启了新的一轮。复杂度

#include<bits/stdc++.h>

using namespace std;
using i64 = long long;
#define endl '\n'

constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

void solve() {
    int n;
    cin >> n;

    vector<i64> g(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> g[i];
    }

    vector<vector<i64>> dp(n + 1, vector<i64> (1 << 4, -1));
    dp[0][0] = 0;

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 4; j++) {
            if (i < j + 1) {
                continue;
            }
            for (int k = 0; k < (1 << 4); k++) {
                if (!(k & (1 << j)) && dp[i - (j + 1)][k] >= 0) {
                    dp[i][k | (1 << j)] = max(dp[i][k | (1 << j)], dp[i - (j + 1)][k] + g[i]);

                } else if (k == (1 << 4) - 1 && dp[i - (j + 1)][k] >= 0) {
                    dp[i][1 << j] = max(dp[i][1 << j], dp[i - (j + 1)][k] + g[i]);
                }
            }
        }
    }

    i64 ans = -1;
    for (int i = 0; i < (1 << 4); i++) {
        ans = max(ans, dp[n][i]);
    }

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 

    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

小美的彩带

小美的彩带是由一条长度为 的彩带一直无限循环得到的,彩带的每一个位置都有一个颜色,用 表示。因此当 时,

小美每次会从左往后或从右往左剪一段长度为 的彩带,她想知道她每次剪下来的彩带有多少种颜色。

题解:这题的题面写的非常垃圾,主要注意两个问题: 前一次操作对后一次操作可能是有影响的,也就是操作之间不是独立的。 从左往后剪的起点是最左端,从右往左剪的起点是最右端。

注意到这两点后就比较简单了,求区间内有多少种不同的数,也是经典问题,不用多说,直接套个可持久化线段树。复杂度

#include<bits/stdc++.h>

using namespace std;
using i64 = long long;
#define endl '\n'

constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

constexpr int N = 4e5 + 5;
struct node{
    int l, r, num;
}tree[N * 100];
int S = 0;
int root[N], a[N], nxt[N];
map<int, int> mp;
void update(int &x, int y, int l, int r, int dex) {
    x = ++S; 
    tree[x] = tree[y]; 
    tree[x].num++;
    if (l == r) {
        return;
    }
    int mid = (l + r) >> 1;
    if (dex <= mid) {
        update(tree[x].l, tree[y].l, l, mid, dex);
    } else {
        update(tree[x].r, tree[y].r, mid + 1, r, dex);
    }
}

int query(int x, int y, int l, int r, int xx, int yy) {
    if (xx <= l && r <= yy) {
        return tree[y].num - tree[x].num;
    }
    int mid = (l + r) >> 1;
    int res = 0;
    if (xx <= mid) {
        res += query(tree[x].l, tree[y].l, l, mid, xx, yy);
    } if (yy > mid) {
        res += query(tree[x].r, tree[y].r, mid + 1, r, xx, yy);
    }
    return res;
}

void solve() {
    int n, q;
    cin >> n >> q;
    n *= 2;

    for (int i = 1; i <= n / 2; i++) {
        cin >> a[i];
        a[n / 2 + i] = a[i];
    }

    mp.clear();
    for (int i = n; i >= 1; i--) {
        if (!mp.count(a[i])) {
            nxt[i] = n + 1;
        } else {
            nxt[i] = mp[a[i]];
        }
        mp[a[i]] = i;
    }

    for (int i = 1; i <= n; i++) {
        update(root[i], root[i - 1], 1, n + 1, nxt[i]);
    }

    int l = 1, r = n;
    while (q--) {
        string x;
        int y;
        cin >> x >> y;

        auto ask = [&](int u, int v) -> int {
            return query(root[u - 1], root[v], 1, n + 1, v + 1, n + 1);
        };

        if (x == "L") {
            if (l + y - 1 > n) {
                int ans = ask(1, n / 2);
                cout << ans << endl;
            } else {
                int ans = ask(l, l + y - 1);
                cout << ans << endl;
            }
            y %= n;
            l = l + y;
            if (l > n / 2) {
                l -= n / 2;
            }
            if (l > n / 2) {
                l -= n / 2;
            }
            assert(l >= 1 && l <= n / 2);

        } else {
            if (r - y + 1 < 1) {
                int ans = ask(1, n / 2);
                cout << ans << endl;
            } else {
                int ans = ask(r - y + 1, r);
                cout << ans << endl;
            }
            y %= n;
            r = r - y;
            if (r <= n / 2) {
                r += n / 2;
            }
            if (r <= n / 2) {
                r += n / 2;
            }
            assert(r > n / 2 && r <= n);
        }
    }

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 

    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   
#秋招##美团2025届秋招[话题]#
全部评论
t3我累个可持久化线段树
点赞 回复 分享
发布于 09-23 10:10 广东

相关推荐

鼗:四级有点难绷,感觉能拿国家励志奖学金,学习能力应该蛮强的,四级确实不重要,但是拿这个卡你可是很恶心啊
点赞 评论 收藏
分享
点赞 评论 收藏
分享
2 4 评论
分享
牛客网
牛客企业服务