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: