見出し画像

RustでAtCoderの過去問をやってみた

モダンな言語を使って他のエンジニアと差別化したいと思ったことはりませんか?
今回はモダンな言語であるRustで競技プログラミングAtcoderをやってみました。

なぜ競技プログラミングでRustなどのモダンな言語を使ったのかというと、モダン言語の書き方やアルゴリズムの組み方をトライアンドエラーしながら学習でき、点数として出来具合が表示されるため技術力に自信がつくと思ったからです。

前半ではRustとAtcoderについて、後半には実際にRustで回答したコードを記載しました。これを機にRustに挑戦してみましょう!


Rust

Rustの概要

Rustはメモリ安全性、並行性、およびパフォーマンスに焦点を当てて設計されたプログラミング言語で、Mozillaによって開発されました。GoogleやMicrosoftなど大手IT企業からエンジニアまでとても注目されている言語で、180ヶ国7万3,000人以上の開発者を対象に行った調査「Stack Overflow Developer Survey 2022」に7年連続で「開発者がもっとも愛するプログラミング言語」として選出されています。

Rustの良さがまとまっている記事があるので気になる方は下のサムネイルを見てみてください!

MicrosoftのRust講座

Microsoftにはプログラミングやインフラのトレーニングが用意されていて、Rustのチュートリアルもあります。

Rustの特徴を問題形式に出題されていたり手を動かしながらRustを勉強できるのでおすすめです。

手軽に始めるには

Rustを手軽に始めたい方はブラウザで実行できる「Rust Playground」があります。パソコンに実行環境を作る前に試したい方は活用してみましょう!

パソコンにインストールするには

パソコンにインストールして使ってみたい方は下のサムネイルを参考にしてみてください!

Atcoder

Atcoder概要

Atcoderは競技プログラミングサイトで、お題に沿って自分の好きな言語でプログラムを記載して点数を競うサイトです。

最近はプログラマー・エンジニアだけでなく、プログラミングに挑戦する未経験者も参加しています。プログラミングを学ぶことで論理的な思考や課題解決能力が上がります。

RustでAtcoderチュートリアルを解く

それではいよいよRustでAtcoderの問題を解いていきます。コードは以下の記事を参考にしてRustを書いていきました。

Atcoderの問題は下のサムネイルから見れます。

ABC086A - Product

use std::io;

fn main(){
  // 1つ目の整数を受け入れる
  let mut input_a_b = String::new();
  io::stdin().read_line(&mut input_a_b).expect("Failed");
  
  // 2つの整数を受け入れ、分割する
  let mut iter = input_a_b.trim().split_whitespace();
  let a:i32 = iter.next().expect("Failed").parse().expect("Failed");
  let b:i32 = iter.next().expect("Failed").parse().expect("Failed");
  
  // a と b の積が偶数か奇数か判定する
  if (a *b %2) == 0{
    println!("Even");
  } else{
    println!("Odd");
  }
}

ABC081A - Placing Marbles

use std::io;

fn main(){
   // 文字列を標準入力から読み取ります。
   let mut s = String::new();
   io::stdin().read_line(&mut s).expect("Failed");

    // '1' の数を数えるためのカウンターを初期化します。
    let mut count = 0;
    
    // 各桁が '1' であるかをチェックし、カウンターを増やします。
    if s.chars().nth(0) == Some('1') {count += 1}
    if s.chars().nth(1) == Some('1') {count += 1}
    if s.chars().nth(2) == Some('1') {count += 1}

    // 結果を出力します。
    println!("{}",count)
}

ABC081B - Shift only

use std::io;

fn main(){
  // 整数を受け入れる
  let mut input_n = String::new();
  io::stdin().read_line(&mut input_n).expect("Failed");
  let n:usize = input_n.trim().parse().expect("Failed");
  
  // 受け入れた整数を配列にする
  let mut input = String::new();
  io::stdin().read_line(&mut input).expect("Failed");
  let mut a:Vec<i32> = input
  .trim()
  .split_whitespace()
  .map(|x| x.parse().expect("Failed"))
  .collect();
  
  // 出力する整数を初期化
  let mut res = 0;
  
  // 操作回数を判定
  for _ in 0..n{
     let mut exist_odd = a.iter().any(|x| x % 2 != 0 );
    if exist_odd {
      break;
    }
    for i in 0..n {
      a[i] /= 2;
    }
    res += 1;
  }
  
  println!("{}",res);
}

ABC087B - Coins

use std::io;


fn main(){

// 500 円玉の最大枚数を入力する
let mut input_a = String::new();
io::stdin().read_line(&mut input_a).expect("Failed A");
let a:i32 = input_a.trim().parse().expect("Failed parse A");

// 100 円玉の最大枚数を入力する
let mut input_b = String::new();
io::stdin().read_line(&mut input_b).expect("Failed B");
let b:i32 = input_b.trim().parse().expect("Failed parse B");

// 50 円玉の最大枚数を入力する
let mut input_c = String::new();
io::stdin().read_line(&mut input_c).expect("Failed C");
let c:i32 = input_c.trim().parse().expect("Faild parse C");

// 合計金額を入力する
let mut input_x = String::new();
io::stdin().read_line(&mut input_x).expect("Failed X");
let x:i32 = input_x.trim().parse().expect("Failed parse X");


// 何通りあるかのカウントを初期化する
let mut res = 0;

// 500 * A + 100 * B + 50 * C == X だったらポイント

// そうではなかったらパス
for i in 0..=a{
  for j in 0..=b{
    for k in 0..=c{
    let total = 500 * i + 100 * j + 50 * k;
    if total == x{
    res += 1;
      
    }
    
    }
  }
}

// 何通りあるか出力する
println!("{}",res);

}

ABC083B - Some Sums

use std::io;

// 各桁の和を計算する関数
fn add_num(mut n:u32)->u32{
let mut sum:u32 = 0;
  while n > 0{
  sum += n % 10;
  n /= 10;
  }
  sum
}

fn main(){
//   数値を取り込み
  let mut input = String::new();
  io::stdin().read_line(&mut input).unwrap();
//   分割する
  let mut iter = input.trim().split_whitespace();

  let mut n:u32 = iter.next().unwrap().parse().unwrap();
  let mut a:u32 = iter.next().unwrap().parse().unwrap();
  let mut b:u32 = iter.next().unwrap().parse().unwrap();

  let mut total:u32 = 0;
  
//   和が A 以上 B 以下である数値の総和
  for i in 1..=n{
    let sum = add_num(i);
    if a <= sum && sum <= b {
      total += i
    }
  }
  
  println!("{}",total)

}

ABC088B - Card Game for Two

use std::io;

fn main() {
    // 数値を取り込み
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();
    let n: usize = input.trim().parse().expect("Failed to parse input as integer");
    // 数値を取り込み
    input.clear();
    io::stdin().read_line(&mut input).unwrap();
    // 配列に格納する
    let mut a: Vec<i32> = input
        .trim()
        .split_whitespace()
        .map(|x| x.parse().expect("Failed to parse input as integer"))
        .collect();
    // 大きい順にソート
    a.sort_by(|a, b| b.cmp(a));

    let mut alice = 0;
    let mut bob = 0;
    
    // 振り分け
    for (i, &num) in a.iter().enumerate() {
        if i % 2 == 0 {
            alice += num;
        } else {
            bob += num;
        }
    }

    println!("{}", alice - bob);
}

ABC085B - Kagami Mochi

use std::io;
use std::collections::HashSet;

fn main(){
    // 数値を入力
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Failed read line");
    let n:usize = input.trim().parse().unwrap();
    
    let mut list:Vec<usize> = Vec::new();
    // 入力された数値を配列に格納する
    for _ in 0..n{
        input.clear();
        io::stdin().read_line(&mut input).expect("Failed read line");
        let n:usize = input.trim().parse().unwrap();
        
        list.push(n);
    }
    // 重複しない数値にする
    let res:HashSet<usize> = list.into_iter().collect();
    
    println!("{}",res.len());
}

ABC085C - Otoshidama

use std::io;

fn main(){
  // 入力された文を分割する
  let mut input = String::new();
  io::stdin().read_line(&mut input).expect("Failed read line");
  let mut iter = input.trim().split_whitespace();
  
  // 分割した数値をそれぞれの変数に格納する
  let number:i32 = iter.next().unwrap().parse().unwrap();
  let yen:i32 = iter.next().unwrap().parse().unwrap();
  
  // 初期値を設定する
  let mut res10000 = -1;
  let mut res5000 = -1;
  let mut res1000 = -1;
  
  // 条件に合う枚数を計算する
  for a in 0..=number{
    for b in 0..=number-a{
      let c = number - a - b;
      let total = 10000 * a + 5000 * b + 1000 * c;
      
      if total == yen{
        res10000 = a;
        res5000 = b;
        res1000 = c;
      }
    }
  }
  
  println!("{} {} {}",res10000,res5000,res1000);
  
}

ABC049C - 白昼夢

use std::io;

fn main(){
  // 入力の読み取り
  let mut input = String::new();
  io::stdin().read_line(&mut input).expect("Failed read line");
  
  // 文字列をリバースする
  let input_rev:String = input.trim().chars().rev().collect();
  
  // 各要素をリバースする
  let divide:Vec<String> = vec!["dream", "dreamer", "erase", "eraser"]
                          .iter()
                          .map(|&d| d.to_string().chars().rev().collect() )
                          .collect();
                          
  
  // 端から切っていく
  let mut can = true;
  let mut i = 0;
  while i < input_rev.len(){
    let mut can2 = false;
    for d in &divide{
      if input_rev[i..].starts_with(d){
        can2 = true;
        i += d.len();
        break;
      }
    }
    
    if !can2{
      can = false;
      break;
    }
  }
  
  // 結果の出力
  if can {
    println!("YES");
  }else{
    println!("NO");
  }
}

ABC086C - Traveling

use std::io;

pub fn main() {
    // 値を入力する
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Failed read line");
    let n:usize = input.trim().parse().unwrap();
    
    let mut plans:Vec<(i64,i64,i64)> = Vec::new();
    // 数値をタプルにして配列に格納する
    for _ in 0..n {
      input.clear();
      io::stdin().read_line(&mut input).expect("Failed read line");
      let mut iter = input.trim().split_whitespace();
      
      let t:i64 = iter.next().unwrap().parse().unwrap();
      let x:i64 = iter.next().unwrap().parse().unwrap();
      let y:i64 = iter.next().unwrap().parse().unwrap();
      
      plans.push((t,x,y));
    }

    let mut t_0 = 0;
    let mut x_0 = 0;
    let mut y_0 = 0;
    let mut res = "Yes";
    
    // 旅行プランを判定する
    for plan in plans {
        let (t_1, x_1, y_1) = (plan.0, plan.1, plan.2);

        let elapsed_time = t_1 - t_0;
        let distance = (x_1 - x_0).abs() + (y_1 - y_0).abs();

        if (elapsed_time - distance < 0) || ((elapsed_time - distance) % 2 != 0) {
            res = "No";
            break;
        }

        t_0 = t_1;
        x_0 = x_1;
        y_0 = y_1;
    }

    println!("{}", res);
}

学習で使った教材

Rust本

手を動かして考えればよくわかる 高効率言語 Rust 書きかた・作りかた

Rustを勉強する必要性やRustプログラミングの基礎から簡単なWebアプリやWebAssemblyなどの高度な技術までをまとめた本です。Pythonで書かれたコードと比較しながら勉強できるのでどのようなコードの作りをしているのかがわかってとても参考になります。Rustの基礎から応用までをじっくりやりたい方におすすめです。

効率がよくて高速、そして今どきの言語!
豊富なサンプルでPythonユーザーに優しい移行点を解説!
これから始める人も、ちょっと挫折してしまった人にも。

△Rustの鬼門「エラー多発」を避ける解説満載
→あえてエラーを出す・出さないコードで比較
△PythonからRustへの道がここにある!
→多くの題材でPythonとRustのコードを併記。違いがわかります
△読むだけでもわかる
→ほとんどのテーマでRustのコードを掲載

手を動かして考えればよくわかる 高効率言語 Rust 書きかた・作りかた

アルゴリズム本

問題解決のための「アルゴリズム×数学」が基礎からしっかり身につく本

アルゴリズムを数学で解説してくれる本。Atcoderの機能を使って本の演習が解けるので知識のインプットだけでなくアウトプットにも活用できる良本です。アルゴリズムの基礎を鍛えたい方や効率的なコードの書き方を学びたい方におすすめです。

アルゴリズムは、プログラミングを用いて問題を解決していくには欠かせない大切な道具です。一方、アルゴリズムを理解し、そして応用できるようになるためには、ある程度の数学的知識と数学的考察力も大切です。

本書では、中学レベル~大学教養レベルの数学的知識のうちアルゴリズム学習に必要なものについて扱うとともに、有名なアルゴリズムと典型的な数学的考察について丁寧に解説します。さらに、知識をしっかり身に付けるための例題・演習問題が全200問掲載されています。

問題解決のための「アルゴリズム×数学」が基礎からしっかり身につく本

Rust動画

動画で学べるプラットフォーム「Udemy」でもRustを学べます。講師と一緒にRustを動かすので書籍ではわからない細かい動作や豆知識が学べます。このコースでは家計簿アプリをRustで作成するセクションがあるのでとても勉強になります。書籍だとあまり学習が進まないけど勉強はしたいという方におすすめです。

未経験からのITエンジニア

IT技術の進化速度が速くなっていっている今、IT技術にアンテナを張っておくことはとても重要です。エンジニアになろうとしている方やそうではない方もITスキルを磨くことで問題解決能力や論理的思考を養うことができます。複雑な課題に対処し、効果的な解決策を見つける能力はどの職種でも重宝されます。

そこで、エンジニア未経験の時にあったらよかったなと思っていた講座をマガジンにまとめました!アプリの基礎がわかるTodoアプリの開発からGit&GitHubでのチーム開発までエンジニアに必要な知識が詰まっています!
エンジニアリングの第一歩として使ってみてください!


「売上げアップに効果的」なキャッチコピーやテキストを作成してくれる国内最大級の「AIコピーライティングツール」
【Catchy】


会議・ミーティングの内容をリアルタイムで文字に起こすAI自動文字起こしサービス
 【Notta】


ブログの記事制作にかかる時間を1/10で制作できる高品質SEO記事生成AIツール
【Value AI Writer byGMO】



いいなと思ったら応援しよう!

ケン吉
サポートよろしくお願いいたします! いただいたサポートの一部ははクリエイターとしての活動費に使わせていただきます! ※ サポートの一部は子供たちの教育などの団体に寄付する予定です。