E - Repunit Trio 解説
by
ngtkana
全探索
「ちょうど \(3\) つのレピュニットの和として表せる整数」は、\( a \ge b \ge c \ge 0\) なる \((a, b, c)\) を用いて \(a - b\) 個の '1'
、\(b - c\) 個の '2'
、\(c +1\) 個の '3'
をこの順に並べてできる数として一意的に表せ、それらの大小は組 \((a, b, c)\) の辞書式順序による大小と一致します。(https://atcoder.jp/contests/abc333/editorial/8004 の受け売りです。)
ところでこれを第 \(a + 2, b + 1, c\) 桁にビットの立っているビット列に対応させると、組 \((a, b, c)\) はちょうど \(3\) 箇所にビットの立っているビット列と一対一対応し、さらにこのビット列の辞書式順序とも一致します。そこで、next_permutation
を使うと楽に全探索ができます。
なお next_permutation
は C++ でしたら、標準ライブラリにあるようです。もしご自分で実装したい場合は、手前味噌ですがこちらのブログで理解を深めていただくのも手かとです。☞ next_permutation と同様に列挙できるもの一覧 - ブログ名
use proconio::input;
use proconio::marker::Usize1;
fn main() {
input! { n: Usize1 }
let mut a = vec![0; n + 3];
a[n..].fill(1);
// `n` 回 `next_permutation` します。
for _ in 0..n {
let i = a.windows(2).rposition(|w| w[0] < w[1]).unwrap();
let j = a.iter().rposition(|x| x > &a[i]).unwrap();
a.swap(i, j);
a[i + 1..].reverse();
}
// 復元します。
let mut ans = String::new();
let mut count = 0;
for x in a {
count += x;
if count != 0 && x == 0 {
ans.push_str(&count.to_string());
}
}
ans.push('3');
println!("{}", ans);
}
投稿日時:
最終更新: