Rustで競プロがやりたい(5)

前回の記事から日が開いてしまった。

competeを使って自動作成して提出もコマンドでできて、と楽だったのだが、Rustを書くのはボロボロだった。 というより、基礎がまだちゃんとしていない状態でPythonでいうClassを書こうとして心が折れてしまった。

ここは一旦基本に忠実ということで、灰Diffを埋めてみる。 competeも一旦使わず、cargo newからまっさらの状態で始めてみる。

proconioは使う方針で。

[dependencies]
proconio = {version = "0.4.3", features = ["derive"]}

テンプレート、fastoutとnon_snake_caseだけ採用する。

use proconio::input;
use proconio::fastout;

#[fastout]
#[allow(non_snake_case)]
fn main() {
    input! {
        ,
    }
    println!();
}

まずは以下の問題から。 atcoder.jp

ACしたときは以下のようなコードになった。

use proconio::input;
use proconio::fastout;

#[fastout]
#[allow(non_snake_case)]
fn main() {
    input! {
        Y: usize,
    }
    let mut ans = "NO";
    if Y % 4 == 0 {
        ans = "YES";
    }
    if Y % 100 == 0 {
        ans = "NO";
    }
    if Y % 400 == 0 {
        ans = "YES";
    }
    println!("{}", ans);
}

しかし実際はかなりつまずいている。 最初はlet mut ans = "";にifをif ~ else if ~ elseで書いて通せるようにした。 すると次のwarningが出た、warningが出てもコードは回せる。

warning: value assigned to `ans` is never read
= help: maybe it is overwritten before being read?
= note: `#[warn(unused_assignments)]` on by default

つまり、ansを他の変数で操作や出力前に確定で別の値に上書きするので注意されている。 下に#[warn(---)]と出ているので#[allow(---)]と書き加えれば出なくなるが、今回はwarningを消したい。

次はlet mut ans;と書き換えてみた。 しかし別のwarningが出てしまう。

warning: variable does not need to be mutable
= note: `#[warn(unused_mut)]` on by default

今回if文で値を書き換えるのが1回だけの為、ミュータブルである必要がないみたいだった。 最終的にlet ans;でwarningが消えたので解決した。

ちなみに普通にWAを出してしまったので最終的にあのACの形になった。

別の問題も見る。 atcoder.jp

2点間の距離は三平方の定理で求めることができる。 ACコードは以下の通り。

use proconio::input;
use proconio::fastout;
use libm::hypot;

#[fastout]
#[allow(non_snake_case)]
fn main() {
    input! {
        N: usize,
    }
    let mut Points = vec![];
    for _ in 0..N {
        input! {
            x: f64,
            y: f64,
        }
        Points.push((x, y));
    }
    let mut ans = 0.0;
    for i in 0..N {
        for j in 0..N {
            let distance = hypot((Points[i].0 - Points[j].0).abs(), (Points[i].1 - Points[j].1).abs());
            if ans < distance {
                ans = distance;
            }
        }
    }
    println!("{}", ans);
}

躓いた点をいくつか挙げる。

まずx, yを入力で受け取るフェーズ。 input!は最初に実行して全て受け取らないといけないと思っていたが、2か所に分けてもいいらしい。 後は空の配列を用意する、そこに追加するといった基本的な処理も、まだ調べないとできなかった。 forも調べないと書けなかった。

次に実際に距離を求めるところ。 Rustはhypotを使うと距離を求めることができる。 なので、use libm::hypot;を書き加え、hypotを使えるようにする。 ちなみにCargo.tomlにlibmを書き加えないと使えない。

[dependencies]
libm = "=0.2.1"

今回tupleで座標を追加したため、[0]ではなく.0で呼び出さないといけなかった。 またhypotはf64しか受け付けていないが、自前で計算を用意する場合でも答えが小数点になる可能性があるので座標の入力をf64で受け取らないといけない。 座標だからusize確定ということがないことを意識しないといけない。

やる度に新しいことがでてきて大変だが、灰Diff埋めでしばらくは頑張っていこうと思う。