2部マッチングの個数にしかみえなくて絶望。
経過した秒数 D の数はたかが知れている。
D を決め打ちしたとすれば、2部グラフが作れる。
+D 秒後と -D 秒後の 2 つしかマッチさせる候補がないので
あるマッチングの連結成分の右側と左側の頂点の個数は
R == L
R + 1 == L
R == L + 1
の3パターンしかない。
R == L のマッチングの個数は 1 通り
R + 1 == L はどこの入次数を 2 にするかで L 通り
R == L + 1 は成り立たない。
後は、連結成分ごとのパターン数の積を計算する。
class OneDimensionalBalls { public: long long countValidGuesses(vector <int> F, vector <int> S) { vector<int> diff; for (int i = 0; i < F.size(); ++i) { for (int j = 0; j < S.size(); ++j) { diff.push_back(abs(F[i] - S[j])); } } sort(diff.begin(), diff.end()); diff.erase(unique(diff.begin(), diff.end()), diff.end()); diff.erase(remove(diff.begin(), diff.end(), 0), diff.end()); sort(F.begin(), F.end()); sort(S.begin(), S.end()); lli ret = 0; for (int d = 0; d < diff.size(); ++d) { cout << diff[d] << endl; vector<lli> v; set<int> vis_F; set<int> vis_S; for (int i = 0; i < F.size(); ++i) { if (vis_F.count(F[i])) continue; int prev_F = vis_F.size(); int prev_S = vis_S.size(); vis_F.insert(F[i]); queue<int> q; for (q.push(F[i]); q.size(); q.pop()) { int n = q.front(); int e[] = {n - diff[d], n + diff[d]}; int f[] = {n - 2 * diff[d], n + 2 * diff[d]}; for (int j = 0; j < 2; ++j) { if (binary_search(S.begin(), S.end(), e[j])) { vis_S.insert(e[j]); if (binary_search(F.begin(), F.end(), f[j]) && !vis_F.count(f[j])) { q.push(f[j]); vis_F.insert(f[j]); } } } } int diff_F = vis_F.size() - prev_F; int diff_S = vis_S.size() - prev_S; if (diff_F == diff_S) v.push_back(1); if (diff_F + 1 == diff_S) v.push_back(diff_S); if (diff_F == diff_S + 1) v.push_back(0); } ret += accumulate(v.begin(), v.end(), 1, multiplies<int>()); } return ret; } };