2024.3.16美团笔试

165 阅读2分钟

前面三题感觉还行,4 5没写出来,暴力打了70%和10%

逆序对这个算法进阶指南有提到~~

逆序对的两种解法:

  • 归并排序:cnt +=mid- i+1
  • 树状数组:tree的index是数字的值,value是数字出现次数。get(n) - get(a[i])当前数对后面的贡献,get(a[i] - 1)是变为负数后会对前面产生的贡献

4 众数和

一个由1和2组成的数组,求每个区间众数和

input
3
2 1 2
output
9

[2],[2,1,2],[2]的众数是 2.

[2,1],[1],[1,2]的众数是 1.

因此答案是 9.

思路:将1转换为-1,将2转换为+1,使用前缀和的方式来判断一个区间内2的数量是否多于1的数量,从而推导出众数

为了区间和的计算方便,这里采用前缀和来进行处理:

img

树状数组下标表示当前位置的前缀和值

值表示前缀和值出现的次数

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll N = 2e6 + 10;
ll t[N];
ll n;
#define debug(x) cout << #x << " = " << x << endl
// tree

ll lowbit(ll x) {
    return x & -x;
}

// add
void add(ll x, ll v) {
    for (ll i = x; i <= n + n + 1; i += lowbit(i)) {
        t[i] += v;
    }
}

// get
ll get(ll x) {
    ll res = 0;
    for (ll i = x; i; i -= lowbit(i)) {
        res += t[i];
    }
    return res;
}

// 1. we can make 1 -> -1, 2 -> 1
// then, [l, r] 的区间和即2-1的数量
// if >0 mean 2的数量多, else 1的数量多
// we can use pre
int main() {
    cin >> n;
    ll ans = 0, res = 0;
    add(n + 1, 1);
    for (ll i = 1; i <= n; i++) {
        ll tm;
        cin >> tm;
        if (tm == 1) {
            ans -= 1;
        } else {
            ans += 1;
        }
        // [-n, n] -> [1, 2n+1]
        // res to store the number of 2
        res += get(ans + n);
        debug(res);
        add(ans + n + 1, 1);
    }
    ll r = n * (n + 1) / 2 - res;
    cout << res * 2 + r;
    return 0;
}

5 排列

给你一个排列a[n],
她定义f(i)为:将第i个元素取反后,形成的数组的逆序对数量。求f(1)到f(n)的值。排列是指一个长度为n的数组,1到n每个元素恰好出现了一次。

img

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll N = 2e6 + 10;

#define debug(x) cout << #x << " = " << x << endl
ll t[N], a[N];
ll left_[N], right_[N];
ll n;

ll lowbit(ll x) {
    return x & -x;
}

ll get(ll x) {
    ll res = 0;
    for (int i = x; i; i -= lowbit(i)) {
        res += t[i];
    }
    return res;
}

void add(ll x, ll v) {
    for (int i = x; i <= n; i += lowbit(i)) {
        t[i] += v;
    }
}

// tree
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    cin >> n;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        left_[i] = get(n) - get(a[i]);
        ans += left_[i];
        add(a[i], 1);
    }
    memset(t, 0, sizeof t);
    for (int i = n; i; i--) {
        right_[i] = get(a[i] - 1);
        add(a[i], 1);
    }
    for (int i = 1; i <= n; i++) {
        cout << ans - left_[i] - right_[i] + i - 1 << (i == n ? " " : "\n");
    }
    return 0;
}

本文使用 文章同步助手 同步