AtCoder

ABC346 E問題(Paint)を解く

AtCoder_ABC346_E

AtCoder が提供しているABC(AtCoder Beginner Contest)346 のE問題をC++とPythonで解いてみました。ABC346は、2024年3月23日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

E問題 Paint(Difficulty : 1053)

問題はリンク先をご覧ください。

ABC346 E問題 Paint

操作を逆に考えることによって解くことができます。AtCoder Problems による Difficulty は 1053 でした。

解答案

操作を逆に考えます。以下の順に処理していきます。

  • 行の場合(Ti=1)
    • すでにその行が塗られていた場合は、この操作は無視する。
    • 指定された色のマスの個数を増やす。
      • 増やす個数は、行の個数(W)から、この後に塗られる(先に処理されている)列の数を引く。
    • その行を塗られていることに更新して、その行を使われていると印をつける。
  • 列の場合(Ti=2)も行と列を入れ替えて同様に処理していきます。

C++ プログラム例(ABC346E)

上でまとめた処理をするために以下のコンテナを用意します。

  • その色で塗られている個数を記憶する map コンテナ color:色番号と個数を組で管理します。
  • ある行または列が、どの色で塗られているか記憶する vector コンテナ color_h または color_w:初期値は-1で、塗った色を記憶します。操作の逆順に処理するため、このコンテナの値は、一度しか更新しません。
  • すでに塗られている行または列を記憶する set コンテナ used_h または used_w:色が塗られた行または列を格納していきます。color を更新する場合に、このコンテナの個数を使います。

上で確認した順番に処理していきます(25ー39行目)。すべて処理できたら、初期値の0になっているマスの個数を求めます。注意は、色0で塗られる場合もあることです。また、コンテナ color に格納するとき(29、36行目)に、結果が0になっていることもあります。このため、1個以上の値を持つ色番号の個数を size として求めておきます。

以下が、C++プログラムとなります。

#include <bits/stdc++.h>
using namespace std;

typedef long long int ll;

int main()
{
	ll h, w, m;
	cin >> h >> w >> m;
	vector<ll> t(m);
	vector<ll> a(m);
	vector<ll> x(m);
	for (int i = 0; i < m; ++i) {
		cin >> t[i] >> a[i] >> x[i];
		--a[i];
	}

	map<ll, ll> color;
	vector<ll> color_h(h, -1);
	vector<ll> color_w(w, -1);
	set<ll> used_h;
	set<ll> used_w;

	for (int i = m - 1; i >= 0; --i) {
		if (t[i] == 1) {
			if (color_h[a[i]] != -1) {
				continue;
			}
			color[x[i]] += w - used_w.size();
			color_h[a[i]] = x[i];
			used_h.insert(a[i]);
		} else if (t[i] == 2) {
			if (color_w[a[i]] != -1) {
				continue;
			}
			color[x[i]] += h - used_h.size();
			color_w[a[i]] = x[i];
			used_w.insert(a[i]);
		}
	}

	ll color_0 = h * w;
	for (auto e : color) {
		if (e.first != 0) {
			color_0 -= e.second;
		}
	}
	color[0] = color_0;
	int size = 0;
	for (auto e : color) {
		if (e.second != 0) {
			++size;
		}
	}
	cout << size << endl;
	for (auto e : color) {
		if (e.second != 0) {
			cout << e.first << " " << e.second << endl;
		}
	}

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

Python プログラム例(ABC346E)

Python 版も基本的な考え方は同じです。連想配列は、defaultdict を使いました。defaultdict は順序がないため、リスト keys に対象を格納してソートして出力しました。以下となります。

"""AtCoder Beginner Contest 346 E"""
from collections import defaultdict

h, w, m = map(int, input().split())
t = [0] * m
a = [0] * m
x = [0] * m
for i in range(m):
    t[i], a[i], x[i] = map(int, input().split())
    a[i] -= 1

color = defaultdict(int)
color_h = [-1] * h
color_w = [-1] * w
used_h = set()
used_w = set()

for i in range(m - 1, -1, -1):
    if t[i] == 1:
        if color_h[a[i]] != -1:
            continue
        color[x[i]] += w - len(used_w)
        color_h[a[i]] = x[i]
        used_h.add(a[i])
    elif t[i] == 2:
        if color_w[a[i]] != -1:
            continue
        color[x[i]] += h - len(used_h)
        color_w[a[i]] = x[i]
        used_w.add(a[i])

color_0 = h * w
keys = []
for key, value in color.items():
    if key != 0 and value != 0:
        color_0 -= value
        keys.append(key)
if color_0 != 0:
    color[0] = color_0
    keys.append(0)

keys.sort()
print(len(keys))
for key in keys:
    print(key, color[key])

こちらも「AC」と判定されました。

最後に

コンテスト中に、このE問題を解くことができました。E問題が解けるとうれしいです。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA