领奖台数


领奖台数

题意:给定任意一个序列\(a_1,\cdots, a_n\),其中没有重复元素。如果\(i < j < k\)\(a_j > a_i > a_k\),三个数字的大小关系就像运动会颁奖时的领奖台。于是我们称序列中满足该条件的三元组\((i,j,k)\)的个数为序列的领奖台数。设计一个算法来计算序列的领奖台数。

输入:第一行包含一个正整数\(n\),表示输入序列的长度。\(n \le 1000000\)

? 第二行输入序列元素\(a_1,...,a_n\)组成,每个元素用空格分隔。\(a_i \in Z, |a_i| \le 10^9\)

输出:输出同时满足条件的三元组个数

solution:树状数组 + 容斥 + 思维

  • 即求"231"三元组个数,\(res\) = \(a_i>a_k\)\(a_j>a_k\)的个数 \(-\) \(a_i > a_j > a_k\)的个数
  • 两个子问题可使用树状数组方便求得,并且题中保证无重复元素,因此无需考虑 \(a_i = a_j > a_k\) 的情况
#include 

using namespace std;
using ll = long long;

struct Fenwick {
    const int n;
    std::vector tr;
    Fenwick(int n) : n(n), tr(n + 1, 0) {}
    void add(int x, int v) {
        for (int i = x; i <= n; i += i & -i) {
            tr[i] += v;
        }
    }
    int sum(int x) {
        int res = 0;
        for (int i = x; i; i -= i & -i) {
            res += tr[i];
        }
        return res;
    }
};

int main()
{
    int n; cin >> n;

    std::vectora(n);

    for(int i = 0; i < n; ++i) cin >> a[i];

    Fenwick fen(n);

    auto s = a;
    sort(s.begin(), s.end());
    auto q = [&](int x) {
        return lower_bound(s.begin(), s.end(), x) - s.begin() + 1;
    };

    std::vectorG(n);
    for(int i = 0; i < n; ++i) {
        int x = q(a[i]);
        G[i] = fen.sum(n) - fen.sum(x);
        fen.add(x, 1);
    }

    Fenwick fen1(n);
    std::vectorL(n);
    for(int i = n - 1; i >= 0; --i){
        int x = q(a[i]);
        L[i] = fen1.sum(x - 1);
        fen1.add(x, 1);
    }

    ll res = 0;
    for(int i = 0; i < n; ++i) {
        res += 1ll * G[i] * (G[i] - 1) / 2 - 1ll * L[i] * G[i];
    }
    
    cout << res << endl;

    return 0;
}

相关