LoginSignup
0
0

More than 5 years have passed since last update.

オフラインリアルタイムどう書く E24 の実装例(腕力版, Rust)

Last updated at Posted at 2018-11-18

問題 : http://nabetani.sakura.ne.jp/hena/orde24tancho/
実装リンク集 : https://qiita.com/Nabetani/items/928d6a94d83c21ef64d7

次回のイベントは 12/8。
詳しくは
https://yhpg.doorkeeper.jp/events/82699
を御覧ください。
まだ問題も決まってないけど、 Rust での実装例を用意したいと思っている(未定) ので、Rust 好きの方も是非。

で。
https://qiita.com/Nabetani/items/e979f3575f82916960c6 を移植した。
実装例は以下の通り。

Rust
const NUMS: &'static str = "0123456789abcdefghijklmnopqrstuvwxyz";

fn digit_values(digits: &mut Vec<i64>, mut num: i64, base: i64) {
    digits.clear();
    loop {
        digits.push(num % base);
        num /= base;
        if num == 0 {
            return;
        }
    }
}

fn digit_text(num: i64, base: i64) -> String {
    let mut digits: Vec<i64> = Vec::new();
    digit_values(&mut digits, num, base);
    digits.reverse();
    digits
        .iter()
        .map(|c| (NUMS.as_bytes()[*c as usize] as char).to_string())
        .collect::<Vec<String>>()
        .join("")
}

fn maxvalue(base: i64) -> i64 {
    let mut r = 0i64;
    for i in 1..base {
        r = r.wrapping_mul(base);
        r = r.wrapping_add(i);
        if r < 0 {
            return i64::max_value();
        }
    }
    r + 1
}

fn is_mono(digits: &mut Vec<i64>, num: i64, base: i64) -> bool {
    digit_values(digits, num, base);
    for s in 1usize..digits.len() {
        let c0 = digits[s - 1];
        let c1 = digits[s];
        if c0 <= c1 {
            return false;
        }
    }
    true
}

fn solve_impl(base: i64, ord: i64) -> i64 {
    let mut count = 0;
    if (1i64 << (base - 1)) < ord {
        return 0;
    }
    let max = maxvalue(base);
    let mut digits: Vec<i64> = Vec::new();
    for i in 1i64..max {
        if is_mono(&mut digits, i, base) {
            count += 1;
            if count == ord {
                return i;
            }
        }
    }
    0
}

fn solve(src: &String) -> String {
    let nums = src
        .split(",")
        .map(|e| e.parse::<i64>().unwrap())
        .collect::<Vec<i64>>();
    let ans = solve_impl(nums[0], nums[1]);
    return if ans == 0 {
        "-".to_string()
    } else {
        digit_text(ans, nums[0])
    };
}

fn test(num: i32, src: String, expected: String) {
    let actual = solve(&src);
    let okay = actual == expected;
    println!(
        "{}, {}, src: {}, act: {}, exp: {}",
        num,
        if okay { "ok" } else { "**NG**" },
        src,
        actual,
        expected
    );
}

macro_rules! test {
    ($n:expr, $x:expr, $y:expr) => {
        test($n, $x.to_string(), $y.to_string());
    };
}

fn main() {
    test!(0, "16,333", "38e");
    test!(1, "2,100", "-");
    test!(2, "2,1", "1");
    test!(3, "2,2", "-");
    // 中略
    test!(56, "36,44811", "abpu");
}

いつもどおりテストの大半は省略。

手元のマシンで 30秒ぐらい。Go と同じぐらい。

まだ高速化の余地があるんじゃないかと疑っているけどよくわからない。

今回は i64 のオーバーフローでパニックになることを知った(デバッグ版だけかな)。便利。

今回の不満は。

ruby なら

ruby
s.each_cons(2).all?{ |c0,c1| c1<c0 }

と書けるところを

Rust
    for s in 1usize..digits.len() {
        let c0 = digits.iter().nth(s - 1).unwrap();
        let c1 = digits.iter().nth(s).unwrap();
        if c0 <= c1 {
            return false;
        }
    }
    true

と書いてしまったところ。なんかいいメソッドあるのかなぁ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0