包除原理の一番簡単な場合を試せる問題
問題概要
個の整数 が与えられる。以下の条件を満たす整数 の組の個数を求めよ。
制約
考えたこと
まず、 という条件がないバージョンを考えてみよう。そのときは単に 個のものから 2 個選ぶ場合の数を求めよ、という問題になる。
通り
となる。これは AtCoder では定期的によく出されている。
補集合を考える
さていよいよ、 という条件を考えていこう。しかしこの条件を考えるのは難しいので、かわりに「逆」の方を数えることにしよう。つまり、逆に
であるような場合の数を数えることにしよう。その答えを としたとき、 を出力すれば OK。
の値ごとに分類
さて、逆の方は数えやすい。たとえば だと
- 1 が 4 個
- 2 が 1 個
- 3 が 2 個
となる。 となるパターンは「4 個から 2 個を選ぶ場合の数」なので 通りで、 となるパターンは 通りで、 となるパターンは 通りとなる。これらを合計して 通りとなる。
一般に、 の値を数値ごとに分類して、その個数を として の総和を取っていけば OK。
コード
計算量は の値を分類するときに map などを用いた場合、 となる。
#include <bits/stdc++.h> using namespace std; int main() { long long N; cin >> N; map<long long, long long> ma; vector<long long> A(N); for (int i = 0; i < N; ++i) { cin >> A[i]; ma[A[i]]++; } long long P = 0; for (auto it: ma) { long long num = it.second; P += num * (num - 1) / 2; } cout << N * (N - 1) / 2 - P << endl; }