公式

E - 共通部分/Intersection 解説 by Nyaan


この問題は次の手順によって解くことが出来ます。

  • 答えを \(\mathrm{answer}\) とする。\(\mathrm{answer}\) ははじめ \(0\) で初期化されている。
  • 全ての 2 個以上の整数集合の部分集合を列挙する。各部分集合に対して次の操作を行う。
    • 整数集合の共通部分を求める。
    • 共通部分が奇数のみで構成されている場合、\(\mathrm{answer}\)\(1\) を加算する。
  • 操作後の \(\mathrm{answer}\) が答えとなる。

計算量は \(\mathrm{O}(2^N \max(C))\) 程度で十分高速です。

  • 実装例 (C++)
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {
  int N;
  cin >> N;
  vector<vector<int>> A(N);
  for (auto& x : A) {
    int C;
    cin >> C;
    x.resize(C);
    for (auto& y : x) cin >> y;
  }

  auto intersect = [](vector<int> a, vector<int> b) {
    vector<int> c;
    set_intersection(begin(a), end(a), begin(b), end(b), back_inserter(c));
    return c;
  };

  int ans = 0;
  for (int b = 0; b < (1 << N); b++) {
    if (__builtin_popcount(b) < 2) continue;
    vector<int> v = A[__builtin_ctz(b)];
    for (int i = 0; i < N; i++) {
      if ((b >> i) & 1) v = intersect(v, A[i]);
    }
    ans += all_of(begin(v), end(v), [](int x) { return x % 2 == 1; });
  }
  cout << ans << endl;
}

投稿日時:
最終更新: