ビンゴを題材とした問題。行・列・斜めを合わせて 個のラインがあるので、各ラインの空きマス数を管理しよう。
問題概要
のグリッドがあり、上から 行目、左から 列目のマスには整数 が書かれている。
今から ターンの穴あけをする。 ターン目には整数 が宣言される。その整数の穴を開ける。
ビンゴが成立する瞬間のターン数を答えよ。最後までビンゴしない場合は -1 を出力せよ。
制約
考えたこと
ターンが終了するごとに、ビンゴが成立するかどうかを調べたい。次の 個の集合を管理しておくと楽だと思われる。
- 各行について、すでに宣言された整数の集合
- 各列について、すでに宣言された整数の集合
- 左上から右下の対角線について、すでに宣言された整数の集合
- 右上から左下の対角線について、すでに宣言された整数の集合
整数 が宣言されたとき、その整数のあるマス を求めてあげて、
- 行 についての上記集合に整数値 を挿入する
- 列 についての上記集合に整数値 を挿入する
- のとき、左上から右下の対角線についての上記集合に整数値 を挿入する
- のとき、右上から左下の対角線についての上記集合に整数値 を挿入する
としよう。そして、もしその挿入操作によって、集合のサイズが になったならば、そのときのターン数を答えればよい。
コード
#include <bits/stdc++.h> using namespace std; using pint = pair<int,int>; int main() { int N, T; cin >> N >> T; // 各行・各列・斜め方向の、穴の空いた集合を管理する vector<set<int>> lines(N * 2 + 2); // 値 val の穴を開ける // さらに、値 val を含むライン id について、ビンゴが達成したかどうかを返す auto play = [&](int id, int val, int turn) { lines[id].insert(val); if (lines[id].size() >= N) { cout << turn << endl; exit(0); } }; // T ターン for (int turn = 1; turn <= T; ++turn) { int A; cin >> A; --A; int x = A / N, y = A % N; // 行 x を見る play(x, A, turn); // 列 y を見る play(y + N, A, turn); // 左上から右下への対角線を見る if (x == y) play(N * 2, A, turn); // 左上から右下への対角線を見る if (x + y == N - 1) play(N * 2 + 1, A, turn); } cout << -1 << endl; }