質問するログイン新規登録

Q&A

解決済

1回答

147閲覧

Atcoder 競プロ典型90問 「016 - Minimum Coins」における拡張ユークリッドの互除法による解法の一部が分からない

catworld

総合スコア2

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

AtCoder

AtCoderは、日本の競技プログラミングサイト「AtCoder」に関する内容です。

0グッド

0クリップ

投稿2026/08/08 18:10

編集2026/08/08 18:17

0

0

質問内容

Atcoder 競プロ典型90問 「016 - Minimum Coins」の問題(https://atcoder.jp/contests/typical90/tasks/typical90_p )を解説3(https://atcoder.jp/contests/typical90/editorial/1148 )に載っている拡張ユークリッドの互除法による方法で実現しようとしましたが,ソースコード(変更前)ではACを出すことができませんでした.同コンテストから参照できるソースコード(https://github.com/hoso629/kyopro_educational_90/blob/main/016.cpp
を参考にし一部加筆したソースコード(変更後)を投稿することでACは出せましたが,この修正でなぜ問題が解決できるようになるかが分かりません.ご教授お願い致します.

ソースコード(変更前)

Python

1import sys 2sys.setrecursionlimit(10**7) 3 4def main(): 5 n = int(input()) 6 a = list(map(int, input().split())) 7 a.sort() 8 ans = 10000 9 10 # a[1]とa[2]の最大公約数d 11 d = gcd(a[1],a[2]) 12 13 # a[1]*y+a[2]*z=dにおけるy,zの一般解pq[0],pq[1] 14 pq = [0,0] 15 exd_gcd(a[1],a[2],pq) 16 17 # 後の計算のためにa[1]とa[2]を互いに素な値にする 18 a[1] = int(a[1]/d) 19 a[2] = int(a[2]/d) 20 21 # 一番安い硬貨の枚数xを固定する 22 for x in range(0,10000): 23 # 一番安い硬貨だけでn円を越した場合 24 if (n-a[0]*x) < 0: 25 break 26 # a[1]*y+a[2]*z= n-a[0]*x の整数解が存在する場合 27 if (n-a[0]*x) % d == 0: 28 29 # 一般解からa[1]*y+a[2]*z= n-a[0]*xにおける整数解の1つ(y,z)を求める 30 y,z = int(pq[0]*(n-a[0]*x)/d), int(pq[1]*(n-a[0]*x)/d) 31 if y >= 0: 32 # yが0以上の条件を満たす状況においてy+zの最小値を求める 33 t= int(y/a[2]) 34 y -= t*a[2] 35 z += t*a[1] 36 else: 37 # yが0以上の条件を満たす状況においてy+zの最小値を求める 38 t= int((-y+a[2]-1)/a[2]) 39 y += t*a[2] 40 z -= t*a[1] 41 42 # zが整数解にならなかった場合 43 if z < 0: 44 continue 45 46 # コインの総和の最小値を更新 47 ans = min(ans, x+y+z) 48 49 print(int(ans)) 50 51# ユークリッドの互除法 52def gcd(a,b): 53 if a < b: 54 a,b = b,a 55 if b == 0: 56 return a 57 else: 58 return gcd(b, a % b) 59 60# 拡張ユークリッドの互除法(a*pq[0]+b*pq[1]=gcd(a,b)を満たすpq[0],pq[1]の整数解を求める) 61def exd_gcd(a,b,pq): 62 if b == 0: 63 pq[0]=1 64 pq[1]=0 65 return a 66 d = exd_gcd(b, a % b, pq) 67 pq[0],pq[1] = pq[1],pq[0]-int(a/b)*pq[1] 68 return d 69 70main()

ソースコード(変更後)

Python

1import sys 2sys.setrecursionlimit(10**7) 3 4def main(): 5 n = int(input()) 6 a = list(map(int, input().split())) 7 a.sort() 8 ans = 10000 9 10 # 変更点:aの中の順番を変えることで後のループで枚数を固定するコインを 11 # 最も価値が高いものに変更する 12 a[0],a[2] = a[2], a[0] 13 a[1],a[2] = a[2], a[1] 14 15 # (以下同文のため省略)

補足情報

言語:Python (PyPy 3.11-v7.3.20)
不正解のテストケースの内容は非公開

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

guest

回答1

0

ベストアンサー

原因は、割り算(小数点以下切り捨て)をint(a/b)で計算していることです。

Pythonで割り算(小数点以下切り捨て)をint(a/b)と書いた場合、a/bの部分は浮動小数点数で計算され、その後int()で整数に変換されます。その際、a/bの部分で浮動小数点数の誤差が入り込み、正しい結果にならない場合があります。

Pythonで割り算(小数点以下切り捨て)をしたい場合は、a // bと書いてください。

原因から分かる通り、実は変更前後とも正しくない結果を返す場合があります。念のため、変更前後ともうまくいかない入力例を挙げておきます。

760563774 996446692 436843249 760563774

投稿2026/08/09 04:09

編集2026/08/09 04:13
actorbug

総合スコア2574

catworld

2026/08/09 13:05

解決しました. 入力例と共に分かりやすい説明ありがとうございます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問