AtCoder

ABC320 E問題(Somen Nagashi)を解く

AtCoder_ABC320_E

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

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

E問題 Somen Nagashi(Difficulty : 1096)

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

ABC320 E問題 Somen Nagashi

set コンテナや優先度付きキューを使って状況をシミュレートします。AtCoder Problems による Difficulty は 1096 でした。

解答案

基本的な処理は以下となります。row と wait の二つのコンテナを用意します。

  • コンテナ row には、列で待っている人を格納します。そうめんを流すタイミングで、一番小さい数字(人)を取り出します。初期値として、1 から N までを格納します。
  • コンテナ wait には、そうめんを得て列から外れて待つ人を格納します。具体的には、(列に戻る時間, 戻る人) を組で格納します。初期値は、空です。
  • 次にコンテナ wait の要素から、列に戻る時間が早い順番に要素を取り出し、次にそうめんを流すタイミングより前に列に戻る時間の人を row に格納していきます。

コンテナ row と wait では、以下の操作が必要となります。

  • 一番小さい要素を取り出す。
  • コンテナには要素が追加される。

C++ では set または priority_queue を、Python では、heapq を選択すると、この操作を速く行うことができます。

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

set コンテナを使います。上で整理した手順を繰り返します。

  • wait に格納されている要素を(戻る時間が早い順に)取り出して、次にそうめんを流すタイミングより前であれば、row に人を格納して、wait から要素を削除します(24ー27行目)。
  • そうめんが流すタイミングで、row に人がいれば、一番数字が小さい人を取り出して、そうめんの量 wi を加えます。そうめんを得たひとは、戻る時間と合わせて wait に格納して、row から削除します(28ー32行目)。

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

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

typedef long long int ll;

int main()
{
	int n, m;
	cin >> n >> m;
	vector<int> t(m), s(m);
	vector<ll> w(m);
	for (int i = 0; i < m; ++i) {
		cin >> t[i] >> w[i] >> s[i];
	}

	set<int> row;
	for (int i = 1; i <= n; ++i) {
		row.insert(i);
	}
	set<pair<int, int>> wait;

	vector<ll> result(n + 1, 0);
	for (int i = 0; i < m; ++i) {
		while ((!wait.empty())&&((*(wait.begin())).first <= t[i])) {
			row.insert((*(wait.begin())).second);
			wait.erase(*(wait.begin()));
		}
		if (!row.empty()) {
			result[*(row.begin())] += w[i];
			wait.insert(make_pair(t[i] + s[i], *(row.begin())));
			row.erase(*(row.begin()));
		}
	}

	for (int i = 1; i <= n; ++i) {
		cout << result[i] << endl;
	}

	return 0;
}

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

Python プログラム例(ABC320E)

Python には、C++ の set に該当する順序付き集合がありません。ただし、この問題は、優先度付きキュー heapq を使っても解くことができます。

優先度付きキューを使いますが、基本的な考え方は、C++ 版と同じです。列に並んでいる人の番号を格納するキュー row と、待ち行列を管理するキュー wait を用意して、C++ と同じ処理を行います。ただし、heapq は、heappop でキューから値を削除するため、取り出すべきでない場合には、同じ値を heappush で書き戻します(23行目)。

"""AtCoder Beginner Contest 320 E"""
import heapq

n, m = map(int, input().split())
t = [0] * m
w = [0] * m
s = [0] * m
for i in range(m):
    t[i], w[i], s[i] = map(int, input().split())

row = list(range(1, n + 1))
heapq.heapify(row)
wait = []
heapq.heapify(wait)

result = [0] * (n + 1)
for i in range(m):
    while len(wait) > 0:
        wt = heapq.heappop(wait)
        if wt[0] <= t[i]:
            heapq.heappush(row, wt[1])
        else:
            heapq.heappush(wait, wt)
            break
    if len(row) > 0:
        rt = heapq.heappop(row)
        result[rt] += w[i]
        heapq.heappush(wait, (t[i] + s[i], rt))

for i in range(1, n + 1):
    print(result[i])

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

最後に

E問題は、適切なコンテナを選択して状況をシミュレートすることができました。

ABC320は、ABCDEの5問を解くことができて、パフォーマンス 1200 と評価されました。レートも 938 と最高を更新することができました。このような進歩を時々感じることができるため、のんびり ABC 参加を続けようと思います。

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

COMMENT

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

CAPTCHA