这是数学题耶!
题意
给定一个整数 \(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;
}
标签:Trio,frac,ne,Distinct,题解,cnt,long,times,int
From: https://www.cnblogs.com/lw0-blog/p/17364713.html