use num::pow;
fn base_8_to_10(n_8: u128) -> u128 {
let n_str = n_8.to_string();
let mut n_10 = 0;
for (e, x) in n_str.chars().rev().enumerate() {
n_10 += (x as u128 - '0' as u128) * pow(8, e);
}
n_10
}
fn base_10_to_9(mut n_10: u128) -> u128 {
let mut n_9_str = String::new();
while n_10 > 0 {
n_9_str.push(std::char::from_digit((n_10 % 9) as u32, 10).unwrap());
n_10 /= 9;
}
n_9_str
.chars()
.rev()
.collect::<String>()
.parse::<u128>()
.unwrap_or(0)
}
fn rewrite_8_to_5(n: u128) -> u128 {
n.to_string().replace('8', "5").parse::<u128>().unwrap()
}
fn main() {
proconio::input! {
mut n: u128,
k: usize,
}
for _ in 0..k {
n = base_8_to_10(n);
n = base_10_to_9(n);
n = rewrite_8_to_5(n);
}
println!("{}", n);
}
fn base_8_to_10(n_8: u128) -> u128 {...}
では、8進数の数字をひとまず10進数に変換します。この関数で重要なことは、以下の2つです。enumerate()
を利用するchar
を数字に変換したい時は、'0' as u128
を引くfor c in 'a'..='c' {
println!("{} as usize: {}", c, c as usize);
}
for c in '0'..'3' {
println!("{} as usize: {}", c, c as usize);
}
char
を数値に変換すると文字コードに変換されていることが分かります。また、文字コードは '0'..='9'
や 'a'..='z'
などで連続しています。そのため、'2'
などの数字を表す char
を u128
型の数値 2u128
に変換したい場合、'2'
の文字コードから '0'
の文字コードを引くことで実現できます。もちろん、単純に '2' as u128 - 48
としても問題ありません。fn base_10_to_9(mut n_10: u128) -> u128 {...}
では、10進数の数字を9進数に変換しています。ここで注意する点は以下の2つです。std::char::from_digit()
の第1引数は u32
を取るため、変換する。n_9_str
を u128
に変換するとき、unwrap_or(0)
を使用する。(n_10 % 9) as u32
を n_10 as u32 % 9
としてもコンパイルは通るものの、異なる計算結果となる可能性があります。理由としては、今回の問題の入力の最大値は 8^20 であり、これは u32
の最大値である 2^32-1 を上回っているためです。ついでに言及しておくと、今回のコードでは u128
として数値を取り扱っていますが、8^20 < 2^64 なのでおそらく u64
でも大丈夫です。今までpythonを使ってきた弊害で自分はこれに気づくのに時間がかかったので、注意してください。unwrap()
とすると入力が 0 のときに panic
が生じてしまうため注意してください。enumerate()
を使うchar
を数値に変換するときは '0'
の文字コードを引くunwrap_or()
などを使用する