こんにちは、ナナオです。

前回に引き続き競プロを実施していきたいと思います。

今回の問題は以下です。

ABC087B - Coins

実装

以下のような実装を行いました。制約が緩いので全探索ですね。

use proconio::input;

fn main() {
    input! {
        a: u16,
        b: u16,
        c: u16,
        x: u16,
    };
    let mut cnt = 0;
    for i in 0..a + 1 {
        for j in 0..b + 1 {
            for k in 0..c + 1 {
                if 500 * i + 100 * j + 50 * k == x {
                    cnt += 1;
                }
            }
        }
    }
    println!("{}", cnt);
}

これで通りました。

ちょっと物足りなかったので、AIと壁打ちしてもうちょっと早い方法にしました。

考え方としては以下の通りです。

「余り物」計算作戦(計算量:O(AB))

500円玉と100円玉の枚数を決めた時点で、「あと何円足りないか」は計算で出せます。

その足りない分を50円玉でピッタリ埋められるかチェックします。

手順は以下の通りです。

  1. 500円玉を $i$ 枚、100円玉を $j$ 枚選ぶ(ここはループ)。
  2. 残りの金額を計算する: Rem = X - (500i + 100j)
  3. 判定: Rem が 0 以上か?(払いすぎてないか)
  • Rem が 50円玉の合計(50 \ C)以下か?(足りるか)
  • Rem は 50円で割り切れるか?(ピッタリいけるか)

これだけで、50円玉の枚数を1枚ずつ試すループ(レバーC)を丸ごとカットできます!

ということでコードは以下の通りです。

use proconio::input;

fn main() {
    input! {
        a: i16,
        b: i16,
        c: i16,
        x: i16,
    };
    let mut cnt = 0;
    for i in 0..=a {
        for j in 0..=b {
            let rem = x - (500 * i + 100 * j);
            if rem >= 0 && rem <= 50 * c {
                cnt += 1;
            }
        }
    }
    println!("{}", cnt);
}

地味にfor文のあたりも0..=aと少し記法を変えています。こんな書き方があるんですね。便利。

ということで今回はこれで👍