AtCoder

ABC331 C問題(Sum of Numbers Greater Than Me)を解く

AtCoder_ABC331_C

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

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

C問題 Sum of Numbers Greater Than Me(Difficulty : 288)

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

ABC331 C問題 Sum of Numbers Greater Than Me

ソートして累積和を求めておきます。AtCoder Problems による Difficulty は 288 でした。

解答案

数列の長さ $N$ の制約は、$1 \leqq N \leqq 2 \times 10^5$ です。それぞれの a[i] に対して、それより大きな要素を求めるために $N$ 回の比較が必要となり、合わせて計算量は、$N^2 = 4 \times 10^{10}$ となり間に合いません。

ソートして累積和を求めることにより計算量を下げます。

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

配列 a をソートした配列を b とします(15行目)。この配列 b の累積和 s を求めておきます(16ー20行目)。この累積和 s を使うと、[left, right) の半開区間に含まれる要素の全ての和は、s[right] – s[left] で求めることができます。

a[i] より大きな要素の場所を upper_bound で求めます。上記の式から、a[i]より大きな要素全ての和が求まります(23、24行目)。

計算量は、二分探索と合わせて、$O(N \log N)$ と下げることができました。以下が、C++プログラムとなります。

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

typedef long long int ll;

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

	for (int i = 0; i < n; ++i) {
		auto it = upper_bound(b.begin(), b.end(), a[i]);
		cout << s[n] - s[it - b.begin()] << " \n"[i == n - 1];
	}

	return 0;
}

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

Python プログラム例(ABC331C)

Python の bisect.bisect_right は、C++ の upper_bound に相当します(13行目)。結果はリスト result に格納して、まとめて出力しています(15行目)。

"""AtCoder Beginner Contest 331 C"""
import bisect

n = int(input())
a = list(map(int, input().split()))
b = sorted(a)
s = [0] * (n + 1)
for i in range(n):
    s[i + 1] = s[i] + b[i]

result = []
for i in range(n):
    result.append(s[n] - s[bisect.bisect_right(b, a[i])])

print(*result)

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

最後に

事前に累積和を計算しておくことにより、計算量を下げることができました。

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

COMMENT

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

CAPTCHA