abc252_d Distinct Trio 题解

发布时间 2023-04-29 23:51:01作者: luogu_wsy0704

这是数学题耶!

题意

给定一个整数 \(n\) 和一个长度为 \(n\) 的整数序列 \(a\),求满足以下要求的三元组个数:

  • \(1 \leqslant i < j < k \leqslant n\)
  • \(a_i \ne a_j\)\(a_j \ne a_k\)\(a_k \ne a_i\)

思路

先想正着做,好,不会。

正着做不行就反着做,先算出所有情况,再去掉不合法。

  • 所有情况的公式:\(\frac{n \times (n-1) \times (n - 2)}{6}\)
    • 公式小解析:首先不考虑顺序,选掉一个数就少一个,选 \(3\) 个就是 \(n \times (n - 1) \times (n - 2)\)
    • 考虑顺序,去掉不合法,除以 \(6\)
  • 不合法的公式:
    • 不合法的情况就两种:
      • 两个数相同,另一个不同。
      • 三个数都相同。
    • \(cnt_i\) 表示 \(i\) 在序列中的出现次数。
    • 对于一个出现在序列中的整数 \(i\),它对答案的负贡献分为以下两种:
      • \(\frac{cnt_i \times (cnt_i - 1) \times (cnt_i - 2)}{6}\),三个元素都相同,与所有情况同理。
      • \(\frac{cnt_i \times (cnt_i - 1) \times (n - cnt_i)}{2}\),其中两个元素相同需要去重,除以 \(2\),另外一个数可以是非 \(i\) 的任意数。

记得开个 long long

Code

#include <iostream>

using namespace std;
using ll = long long;

const int N = 2e5 + 10;

int n, a[N], cnt[N];
bool f[N];
ll ans; // 记得开 long long

int main () {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    cnt[a[i]]++; // 统计出现次数
  }
  ans = 1ll * n * (n - 1) * (n - 2) / 6; // 所有情况
  for (int i = 1; i <= n; i++) {
    if (f[a[i]]) { // 同一个数不用多次求
      continue;
    }
    f[a[i]] = 1; // 标记
    ans -= 1ll * cnt[a[i]] * (cnt[a[i]] - 1) * (cnt[a[i]] - 2) / 6; // 套用公式
    ans -= 1ll * cnt[a[i]] * (cnt[a[i]] - 1) * (n - cnt[a[i]]) / 2;
  }
  cout << ans;
  return 0;
}