これが ABC の C 問題だったとは...!!!
典型90問の問 4 が結構近いと思った。
問題概要
のグリッド (メモリにおさまらない規模) が与えられる。そのうちの 個のマスには飴が置いてある。
次の条件を満たすマスの個数を求めよ。
「そのマスと行または列が等しいマス ( 個ある) のうち、飴のあるマスの個数がちょうど 個である」
制約
考えたこと
競プロ典型90問の問 4 と同様に、次の値をあらかじめ前処理しておこう。
yoko[i]
← 行目に飴マスが何個あるかtate[j]
← 列目に飴マスが何個あるか
このとき、マス と行または列が等しい飴マスの個数は次のように解釈できる。
- マス が飴マスでない場合:
yoko[i]
+tate[j]
- マス が飴マスである場合:
yoko[i]
+tate[j]
- 1
このことを踏まえて、次の手順で求められることがわかる。次の値を求めていくことにしよう。
- :
yoko[i] + tate[j] == K
であるようなマス の個数 - :
yoko[i] + tate[j] == K
であって、 自身が飴マスであるような個数 - :
yoko[i] + tate[j] == K + 1
であって、 自身が飴マスであるような個数
このとき、答えは となる。
まず yoko
, tate
は の計算量で求められる。 は各 行に対して tate[j]
が K - yoko[i]
になるような を数えることで求められる (tate
をヒストグラム化することでできる)。 は 個の飴マスを順に見ることで でできる。
全体として計算量は となる。
コード
#include <bits/stdc++.h> using namespace std; int main() { // 入力 long long H, W, K, N; cin >> H >> W >> K >> N; vector<int> X(N), Y(N); for (int i = 0; i < N; ++i) { cin >> X[i] >> Y[i]; --X[i], --Y[i]; } // 各行各列の飴マスの個数 vector<long long> yoko(H, 0); vector<long long> tate(W, 0); for (int i = 0; i < N; ++i) { yoko[X[i]]++; tate[Y[i]]++; } // tate をヒストグラム化 vector<long long> num(N + 1, 0); for (int j = 0; j < W; ++j) num[tate[j]]++; // 各値を求める long long A = 0, B = 0, C = 0; for (int i = 0; i < H; ++i) { if (K >= yoko[i]) A += num[K - yoko[i]]; } for (int i = 0; i < N; ++i) { long long sum = yoko[X[i]] + tate[Y[i]]; if (sum == K) ++B; else if (sum == K + 1) ++C; } cout << A - B + C << endl; }