ABC146 C - Buy an Integer
目次
# 問題
https://atcoder.jp/contests/abc146/tasks/abc146_c
# 入力
A B X
- A, B - を満たす整数
- X - を満たす整数
# 出力
を満たすような最大のを答える問題です.
ただしはの桁数です.
N
# 入出力例
10 7 100
9
# 解説
条件を満たす場合にtrue
を返す関数をcanBuy
とします.
が1以上以下なので、からNを1つずつ大きくしていってcanBuy
を実行します.
そして初めてfalse
を返したらそれより1つ小さい値が答えになります.
これは線形探索なので計算ステップ数的にはとなり間に合いません.
程度に抑える必要があります.
そこでNの性質に着目するとと単調に増加しています.
これはソート済みの配列とみなすことが出来ます.
ソート済みの配列には二分探索が適用できます.
二分探索の場合は計算量なので余裕で間に合います.
二分探索の場合には範囲を漏れなくチェックすることに気をつけることが重要です.
探索範囲の左をleft
、右をright
、その中央をn
、前回のnをprev
とします.
更新ロジックと終了条件を以下のようにすると簡単に漏れなくチェックできます.
更新
n
が買える時、left = n + 1
n
が買えない時、right = n - 1
終了条件は以下どちらかを満たす場合
left
とright
が逆転した場合
n
とprev
が同じ場合
範囲外のについても事前にチェックしておきましょう.
Nの最大値が買える場合にはすべてのが買えます.
1すら買えない場合には何も買えません.
あとは通常の二分探索です.
以下のコードを参照してください.
# 計算量
整数の最大値はなので、これを二分探索すると、
# 解答
#define MAX_N 1000000000
#define MIN_N 1
Int A, B, X;
void input() {
cin >> A >> B >> X;
}
Int d(Int n) {
return to_string(n).length();
}
bool canBuy(Int n) {
return A * n + B * d(n) <= X;
}
void solve() {
// なんでも買える
if (canBuy(MAX_N)) {
cout << MAX_N << endl;
return;
}
// 何も買えない
Int max_n = MIN_N;
if (!canBuy(max_n)) {
cout << 0 << endl;
return;
}
// 最高値を二分探索
Int left = MIN_N+1, right = MAX_N-1;
Int prev = -1, n;
while (left <= right) {
n = (left+right)/2;
if (n == prev) break;
prev = n;
if (canBuy(n)) {
max_n = n;
left = n + 1;
} else {
right = n - 1;
}
}
cout << max_n << endl;
}
int main(void) {
input();
solve();
return 0;
}