Official

D - Magical Cookies Editorial by cn449


基本的には問題文の通りに操作をすればよいですが、同じ行や列にあるクッキーがすべて同じ色か判定する際に時間計算量 \(\Theta(H)\)\(\Theta(W)\) かかるような方法を選択してしまうと、1 回の手続き 1. や 2. に要する時間計算量は \(\Theta(HW)\) となることから、最悪ケースにおいて全体の計算量が \(\Theta(HW(H+W))\) かかって TLE してしまいます。

与えられる色の種類が少ないことを利用して、高速化を考えましょう。与えられる可能性のある色の種類が \(\sigma\) 種類であるとします。本問題において、\(\sigma = 26\) です。各行に対し a, b, \(\ldots\), z の色のクッキーの枚数を管理しながら操作をすることで、同じ行や列にあるクッキーがすべて同じ色か \(O(\sigma)\) で判定することができます。よって同じ色か判定する部分に関しては 時間計算量 \(O(\sigma (H+W)^2)\) でできることがわかりました。クッキーに印をつけることと取り除くことは、各クッキーに対して 1 度しか操作が行われないことから時間計算量 \(O(HW)\) ででき、全体として時間計算量 \(O(\sigma (H+W)^2)\) でこの問題を解くことができました。

実装例
実際に印をつけず、印をつける行と列の番号とクッキーの色を管理した実装をしていることに注意してください。

#include <iostream>
#include <vector>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;

int main() {
	int h, w;
	cin >> h >> w;
	vector<vector<char>> c(h, vector<char>(w));
	rep(i, h) rep(j, w) cin >> c[i][j];
	vector<vector<int>> x(h, vector<int>(26));
	vector<vector<int>> y(w, vector<int>(26));
	rep(i, h) rep(j, w) {
		x[i][c[i][j] - 'a']++;
		y[j][c[i][j] - 'a']++;
	}
	int hc = h, wc = w;
	vector<bool> fx(h), fy(w);
	rep(_, h + w) {
		vector<pair<int, int>> ux, uy;
		rep(i, h) {
			if (fx[i]) continue;
			rep(j, 26) {
				if (x[i][j] == wc && wc >= 2) {
					ux.push_back({ i, j });
				}
			}
		}
		rep(i, w) {
			if (fy[i]) continue;
			rep(j, 26) {
				if (y[i][j] == hc && hc >= 2) {
					uy.push_back({ i, j });
				}
			}
		}
		for (pair<int, int> p : ux) {
			fx[p.first] = true;
			rep(i, w) y[i][p.second]--;
			hc--;
		}
		for (pair<int, int> p : uy) {
			fy[p.first] = true;
			rep(i, h) x[i][p.second]--;
			wc--;
		}
	}
	cout << hc * wc << '\n';
}

posted:
last update: