わたぼこり美味しそう

関西のデータ分析界隈でうろちょろ

AtCoder ABC146のC問題を二分探索を使わずに解いてみる

AtCoder ABC 146のC問題を二分探索を使わずに解いてみました
言語はPythonです
atcoder.jp

整数Nを買うために必要なお金はA×N+B×d(N) [円]ですが
予め桁数を求めることで
A, B, d(N), xはそれぞれ定数となるので


x > A * N + B * d(N)\\
N < \dfrac {x - B * d(N)}{a}\\
N = \dfrac {x - B * d(N)}{a}の整数部分
で求めることができ、for文は桁数を求める際の最大10回分だけで済みます。
以下実装

"""標準入力"""
a, b, x = map(int, input().split())

"""Nが取りうる桁数digitsを求める"""
for n in range(1,10):
    digits = 10**n
    if (a*digits + b*len(str(digits))) > x:
        digits = 10**(n-1)
        break

"""
if文の中身
整数Nが上限(10^9)を超える場合:10^9を出力
購入できる整数Nがない場合:0を出力
digitsを超える桁数をとる場合:ans-1を出力(想定桁数に戻すため)
"""
const = x - len(str(digits)) * b
ans = const // a
if len(str(digits)) >= 10:
    print(10**9)
    
elif ans <= 0:
    print(0)
    
elif len(str(ans)) > len(str(digits)):
    print(ans-1)
    
else:
    print(ans)

最後の出力部分ではコーナーケースごとにif文で分けています

elif len(str(ans)) > len(str(digits)):
    print(ans-1)

特に最後のif文部分についてもう少し詳細に書くと
例えば入力がa = 100, b = 1, x = 1001の場合
最初に桁数を求めた時点ではdigits = 1(0~9の値しか取らない意)になりますが
const = 1001 - 1 * 1 = 1000
ans = 10
となり矛盾が起ります(n敗)

素直に二分探索でやった方がいいですね

おまけの二分探索
a, b, x = map(int, input().split())

"""にぶたん"""
minim = 0
maxim = 10**9 + 1

while maxim - minim > 1:
    int_ave = (minim + maxim)//2
    if (a*int_ave + b*len(str(int_ave))) > x:
        maxim = int_ave
    else:
        minim = int_ave

print(minim)