AtCoder

ABC323 C問題(World Tour Finals)を解く

AtCoder_ABC323_C

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

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

C問題 World Tour Finals(Difficulty : 357)

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

ABC323 C問題 World Tour Finals

各プレイヤーが解けなかった問題から処理していきます。AtCoder Problems による Difficulty は、357 でした。※2023年10月15日 Difficulty を追記しました。

解答案

1からN(最大値100)までのプレイヤーに対して、プレイヤーの数字がボーナス点として与えられます。問題の点数 Ai は、100の倍数となるため、同じ点数になるプレイヤーはいません。このため、この問題は解きやすくなっています。

  • 最初に、それぞれのプレイヤーの点数を求める。
  • プレイヤーの最高点を求める。最高点のプレイヤーは一人となります。
  • それぞれのプレイヤーの解けていない問題から高い点数の問題を選び、最高点を超えるまでその点数を加えていきます。

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

以下は、プログラムの補足です。

  • それぞれのプレイヤー score と最高点 max_score を求めます(17ー27行目)。
  • 自分が最高点の場合、0 を出力します(30ー33行目)。
  • 解けていない問題の点数を優先度付きキューに格納します。
  • キューから高い点数順に取り出し、最高点を超えるまで加えていきます(44ー52行目)。

最終的なC++プログラムは、以下となります。

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

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

	vector<int> score(n, 0);
	int max_score = -1;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			if (s[i][j] == 'o') {
				score[i] += a[j];
			}
		}
		score[i] += i + 1;
		max_score = max(max_score, score[i]);
	}

	for (int i = 0; i < n; ++i) {
		if (score[i] == max_score) {
			cout << 0 << endl;
			continue;
		}

		priority_queue<int> bonus;
		for (int j = 0; j < m; ++j) {
			if (s[i][j] == 'x') {
				bonus.push(a[j]);
			}
		}

		int bonus_score = score[i];
		int result = 0;
		while (1) {
			bonus_score += bonus.top();
			bonus.pop();
			++result;
			if (bonus_score > max_score) {
				cout << result << endl;
				break;
			}
		}
	}

	return 0;
}

上記のプログラムでは、優先度付きキューを使いました。C++ では、multiset でも同じことができます。以下は、multiset を使ったプログラムです。コンテナに関係する行の背景色を変更しておきます。

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

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

	vector<int> score(n, 0);
	int max_score = -1;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			if (s[i][j] == 'o') {
				score[i] += a[j];
			}
		}
		score[i] += i + 1;
		max_score = max(max_score, score[i]);
	}

	for (int i = 0; i < n; ++i) {
		if (score[i] == max_score) {
			cout << 0 << endl;
			continue;
		}

		multiset<int> bonus;
		for (int j = 0; j < m; ++j) {
			if (s[i][j] == 'x') {
				bonus.insert(a[j]);
			}
		}

		int bonus_score = score[i];
		auto it = bonus.rbegin();
		int result = 0;
		while (1) {
			bonus_score += *it;
			++result;
			if (bonus_score > max_score) {
				cout << result << endl;
				break;
			}
			++it;
		}
	}

	return 0;
}

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

Python プログラム例(ABC323C)

Python 版も基本的な考え方は同じです。

heapq モジュールを import することにより、優先度付きキューを使うことができます。heapq が提供するキューは、最小値を取り出します。今回の場合、最大値を取り出したいため、マイナスをつけた値を push して、pop した値にマイナスをつけています(26、31行目)。

"""AtCoder Beginner Contest 323 C"""
import heapq

n, m = map(int, input().split())
a = list(map(int, input().split()))
s = [input() for i in range(n)]

score = [0] * n
max_score = -1
for i in range(n):
    for j in range(m):
        if s[i][j] == 'o':
            score[i] += a[j]
    score[i] += i
    max_score = max(max_score, score[i])

for i in range(n):
    if score[i] == max_score:
        print(0)
        continue

    que = []
    heapq.heapify(que)
    for j in range(m):
        if s[i][j] == 'x':
            heapq.heappush(que, -a[j])

    bonus_score = score[i]
    result = 0
    while True:
        bonus_score += -heapq.heappop(que)
        result += 1
        if bonus_score > max_score:
            print(result)
            break

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

最後に

バーチャルコンテストで解いたときは、最初 set を使っていてWA判定となっていました。Priority_queue を使ってうまく動いた後に、set では要素が重複している場合に動かないことに気づきました。このようなミスは減らしていきたいです。

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

COMMENT

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

CAPTCHA