AtCoder

ABC312 C問題(Invisible Hand)を解く

AtCoder_ABC312_C

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

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

C問題 Invisible Hand(Difficulty : 727)

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

ABC312 C問題 Invisible Hand

解の二分探索を用いて解くことができます。AtCoder Problems による Difficulty は 727 でした。

解答案

二分探索で求めることができます。めぐる式と呼ばれる二分探索の実装を参考にしました。ABC299D問題解説)、ABC309C問題解説)でも解説しています。

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

売ってもよい値段の配列 a と買ってもよい値段の配列 b を読み込んでソートしておきます。めぐる式二分探索の考え方は、29行から39行目で表現されています。このコードは共通で使えます。関数 is_OK と変数 ng と ok の初期値を変更すれば、いろいろな解の二分探索を行うことができます。

関数 is_OK の考え方は以下です。

  • 「X 以下の配列 a の要素数」を seller とします。これは、X 円で売ってよい人数となります(10行目)。seller を求めるために upper_bound を使います。
  • 「X 以上の配列 b の要素数」を buyer とします。これは、X 円で買ってよい人数となります(11行目)。buyer を求めるために lower_bound を使います。
  • seller >= buyer の値を返します(12行目)。

変数 ok の初期値は、109 + 1 にしています(30行目)。これは、以下の入力例の場合、109 + 1 が解になるためです。解が 109 + 1 になるテストケースがコンテストにあり、この初期値を 109 にすると、1つのテストケースでWA(Wrong Answer)判定となります。

1 2
1000000000      
1000000000 1000000000

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

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

int n, m;
vector<int> a;
vector<int> b;

bool is_OK(int mid)
{
	int seller = upper_bound(a.begin(), a.end(), mid) - a.begin();
	int buyer = m - (lower_bound(b.begin(), b.end(), mid) - b.begin());
	return seller >= buyer;
}

int main()
{
	cin >> n >> m;
	a.resize(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
	}
	sort(a.begin(), a.end());
	b.resize(m);
	for (int i = 0; i < m; ++i) {
		cin >> b[i];
	}
	sort(b.begin(), b.end());

	int ng = 0;
	int ok = 1000000001;

	while (abs(ok - ng) > 1) {
		int mid = (ok + ng) / 2;
		if (is_OK(mid)) {
			ok = mid;
		} else {
			ng = mid;
		}
	}

	cout << ok << endl;

	return 0;
}

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

Python プログラム例(ABC312C)

Python 版は C++ 版を移植しました。seller と buyer を求めるために bisect モジュールを使いました。

"""AtCoder Beginner Contest XXX Y"""
import bisect


def is_OK(mid):
    global m

    seller = bisect.bisect_right(a, mid)
    buyer = m - bisect.bisect_left(b, mid)
    return seller >= buyer


n, m = map(int, input().split())
a = list(map(int, input().split()))
a.sort()
b = list(map(int, input().split()))
b.sort()

ng = 0
ok = 10 ** 9 + 1
while abs(ok - ng) > 1:
    mid = (ok + ng) // 2
    if is_OK(mid):
        ok = mid
    else:
        ng = mid

print(ok)

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

最後に

最初、解の二分探索の考え方を学んだときには難しく感じましたが、慣れてきて問題を解くことができるようになりました。

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

COMMENT

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

CAPTCHA