A - フリーマーケットの売上管理 / Flea Market Sales Management Editorial by admin
Gemini 3.0 Flash (Thinking)概要
\(N\) 種類の商品があるフリーマーケットにおいて、\(M\) 回の取引が行われた後の最終的な所持金を求める問題です。各取引ごとに売上の半分(小数点以下切り捨て)が手数料として差し引かれるため、取引ごとに正確に計算を行う必要があります。
考察
この問題を解くためのポイントは以下の3点です。
取引ごとの計算: 手数料は「売上の合計」に対してではなく、「取引ごと」に発生します。例えば、5円の売上が2回あった場合、各取引で \(\lfloor 5/2 \rfloor = 2\) 円の手数料がかかり、手元に残るのは \((5-2) + (5-2) = 6\) 円です。これを合計売上10円に対して一度に計算すると \(\lfloor 10/2 \rfloor = 5\) 円の手数料となり、結果が変わってしまいます。問題文の「その場で支払う」「順番に処理される」という指示通りにシミュレーションする必要があります。
制約と計算量: 商品の種類数 \(N\) とお客さんの数 \(M\) は最大 \(10^5\) です。1回の取引は定数時間 \(O(1)\) で計算できるため、全体で \(O(M)\) の計算量となります。これは実行時間制限内に十分間に合う計算量です。
入力の高速化: Pythonでは
input()を \(M\) 回呼び出すと、入力行数が多い場合に実行時間が長くなることがあります。sys.stdin.read().split()を使って一括で読み込むことで、高速に処理を行うことができます。
アルゴリズム
以下の手順でシミュレーションを行います。
- 初期の所持金 \(S\) を変数(例:
current_cash)に格納します。 - 各商品の価格 \(P_1, P_2, \ldots, P_N\) を配列(リスト)に格納します。このとき、商品番号は1から始まりますが、プログラミング言語の配列は0から始まることが多いため、インデックスの扱いに注意します(商品 \(T_j\) の価格は
P[T_j - 1])。 - 各取引 \((T_j, Q_j)\) について、以下の計算を \(M\) 回繰り返します。
- その取引の売上 \(X = P_{T_j} \times Q_j\) を計算する。
- 手数料 \(F = \lfloor X / 2 \rfloor\) を計算する。
- 所持金に \((X - F)\) を加算する。
- 最終的な所持金を出力します。
計算量
- 時間計算量: \(O(N + M)\)
- 商品価格の読み込みに \(O(N)\)、取引の処理に \(O(M)\) かかります。
- 空間計算量: \(O(N + M)\)
- 商品価格を保持する配列に \(O(N)\)、入力を一括で保持する場合に \(O(N + M)\) のメモリを使用します。
実装のポイント
整数除算: Pythonでは
//演算子を使うことで、小数点以下を切り捨てた整数除算(床関数 \(\lfloor \cdot \rfloor\))を簡単に行えます。1-indexedと0-indexed: 問題文の「\(T_j\) 番目の商品」を配列のインデックスとして使う際は、1を引いて
P[T_j - 1]とする必要があります。大きな数値: 最終的な所持金は \(10^9 + (10^5 \times 10^4 \times 10^4) = 10^{13}\) 程度になる可能性がありますが、Pythonは標準で多倍長整数をサポートしているため、オーバーフローを気にする必要はありません。
ソースコード
import sys
def main():
# 標準入力からすべてのデータを読み込み、空白で分割してリストに格納します
# この方法は大量の入力を高速に処理するのに適しています
input_data = sys.stdin.read().split()
if not input_data:
return
# 1行目のデータ(N: 商品の種類数, M: お客さんの人数, S: 初期の所持金)をパースします
N = int(input_data[0])
M = int(input_data[1])
S = int(input_data[2])
# 2行目のデータ(各商品の価格 P_1, P_2, ..., P_N)をパースします
# 商品番号は1から始まりますが、リストの添字として扱うために0-indexedで管理します
P = list(map(int, input_data[3:3+N]))
# 現在の所持金を管理する変数(初期値は S 円)
current_cash = S
# 3行目以降の購入情報(T_j: 購入した商品の種類, Q_j: 購入個数)を順番に処理します
# 購入情報は input_data の 3+N 番目の要素から始まります
idx = 3 + N
for _ in range(M):
# 商品の種類 T_j と個数 Q_j を取得
t_j = int(input_data[idx])
q_j = int(input_data[idx+1])
idx += 2
# その取引での売上金額 X を計算します
# T_j は1から始まるため、リスト P の添字は t_j - 1 となります
sales = P[t_j - 1] * q_j
# 手数料は売上の半分(小数点以下切り捨て)です
# 最終的な手元の増加分は「売上 - 手数料」となります
# Pythonの // 演算子は小数点以下切り捨ての整数除算を行います
fee = sales // 2
current_cash += (sales - fee)
# すべての取引完了後の所持金を出力します
print(current_cash)
if __name__ == '__main__':
main()
この解説は gemini-3-flash-thinking によって生成されました。
posted:
last update: