🚵‍♀️

【環境構築なし】”超”忙しい方向けのC++競プロ入門

2023/12/04に公開

こんにちは!MYJLab Advent Calendar 2023 9日目を担当します、3年の関根です。

昨日は@baaaさんのLLMを試す記事でした。

クリスマスに食べるものは?という質問にAIが”にゃー”と答えてきたというのがめちゃくちゃ面白かったです笑

さて、私は今年の夏から競プロ(競技プログラミング)を始めました。そこからやっていない期間もあったのですが、最近また熱が入り出して毎日問題を解いています。

競プロを始めたのと同時にC++を始め、そこからずっとC++ユーザなのですが、同学年で競プロをやっている仲間にC++を使っている人がいなくて、実は寂しい思いをしています。そこで、競プロに特化したC++入門記事を作成することでC++仲間を増やそうというのが今回の狙いです。

よろしくお願いします!

なんでC++?

といっても、競プロではPythonやJava, JavaScriptなど主要な言語は大体使えます。そんな状況でいきなり「C++やろうぜ!!」とか言われても怖いと思うので簡単にC++を使うメリットを紹介します。

実行速度が速い

C++はプログラムを実行する際の速度が他の言語に比べて速いという特徴があります。競プロでは提出したプログラムの処理に時間がかかりすぎてしまうと、TLE(時間超過)判定になり、正しい答えが出せていたとしてもアウトになってしまうため、その面で優れているC++は人気が高いです。

情報が豊富

正直これがC++を勉強することの1番のメリットだと思うのですが、C++の方が情報が豊富です。コンテスト終了後に公開される解説コードはほとんどの場合C++で書かれていますし、その他競プロに関連するアルゴリズムやデータ構造についての本もC++で書かれていることが多いです。

そのため、C++がわからない状態だとそういった情報源をうまく活用できず、勉強がしづらくなってしまいます。逆に言えばC++を覚えてしまえばそういった情報を利用できるようになるので一気に世界が広がります!

目標

とりあえず今回は競プロ頻出の「変数定義」「入力・出力」「for・if文」「配列」をマスターすることを目標にします!これができれば一番簡単なA問題であれば解くことができるようになるはずです。

今回利用する実行環境

今回は環境構築の負担を減らすため、Web上で使えるC++実行環境を利用します。
https://cpp.sh/
デフォルトではすでにこんな感じのコードが書かれていると思います。

// Example program
#include <iostream>
#include <string>

int main()
{
  std::string name;
  std::cout << "What is your name? ";
  getline (std::cin, name);
  std::cout << "Hello, " << name << "!\n";
}

まずはこれを以下の内容に書き換えましょう!(コピペでOK)
今回は「main()関数の中に書いたコードが実行される」ということだけ知ってもらえば大丈夫です!

#include <iostream>
#include <string>
using namespace std;

int main(){

    // ここにコードを書いていく

    return 0; // return 0;はプログラムの終了を表す
}

変数の定義

まずは変数の定義について見てみましょう!といっても、他言語の経験があれば難しくはないです。

型 変数名

で定義可能です。型は整数型とかそういうやつです。
例えばintは整数型、stringは文字列型を表します。JavaScriptとかとほぼ同じですね。

例えば、以下のように使います。

int a; // int型変数aを定義
a = 3; // 変数aに3を代入

string s = "MYJ"; // string型変数sを定義し、"MYJ"を代入

なお、C++ではコードの終わりに毎回「;」をつけなくてはならないので気をつけてくださいね。

入力・出力

次に値を受け取り、結果を出力する方法を学びます。「標準入力・標準出力」ってやつです。早速構文を見てみましょう。

入力の構文はこちら!

cin >> 入力対象

出力の構文はこちら!

cout << 出力対象

「>>」と「<<」が見慣れない方がいるかもしれませんが、そういうものだと飲み込んでください。実際の使い方を確認してみましょう!

string input_text; // string型変数input_textを定義

cin >> input_text; // input_textの値を標準入力で受け取る
cout << input_text; // input_textの値を出力

こちらの内容をmain()関数の中に書き込んで青いRunボタンを押して実行します。そうすると、下の方のウィンドウが入力待ち状態になります。好きな文字列を打ってEnterを押してみましょう。
すると、そのすぐ下に入力した文字列が出力されると思います。

なお、入力、出力は続けて書くこともできます。例を見てましょう。

int a, b, c;
cin >> a >> b >> c;
cout << a << " " << b << " " << c;

このように書くことで、まずa,b,cの3つのint型変数の値として入力を3回受け取ったのち、その値をそれぞれ空白で区切って出力させることができます。これも実行してみて動作を確認してみてください。

for文・if文

次に繰り替えし処理を行うためのfor文と条件分岐のためのif文を見ていきます。こちらも他言語の経験があれば難しくはないはずです。

for文の構文はこちら!

for(int i = 0; i < 繰り返したい数; i++){
    // 処理
}

if文の構文はこちら!

if(真偽の判定式){
    // 処理
}

例えば、"Hello!"という文字列を10回表示させ、5回目のHelloの時に"World!"という文字列を表示させてみます。

for(int i = 0; i < 10; i++){
    cout << "Hello";
    if(i == 4){
        cout << "World!";
    }
}

カウンタ変数であるiは0からスタートしているので、iが4の時に5回目のループであることに注意してください。以下のようになっていれば成功です!

5回目のHelloの後にWorld!と出力されていますね。ただ、ちょっと読みづらいので改行させてみましょう。"\n"を出力することで改行させられます。

for(int i = 0; i < 10; i++){
    cout << "Hello" << "\n";
    if(i == 4){
        cout << "World!" << "\n";
    }
}

こうすれば出力の度に改行されて見やすくなります。実際に試してみてください。

配列

ラストは配列です。後少しです、頑張ってください!
早速構文から見ていきましょう。

型名 配列名[要素数]

こんな感じで定義することができます。実際の例を見てましょう。

int arr[10];

このようにすることで、int型で要素数が10の配列を定義できます。配列の特定の要素を指定する場合は

配列名[添え字]

のように書きます。それでは最後に要素数10のint型配列arrに0から9までの整数を代入し、それを出力するプログラムを見てましょう。

int arr[10];
for(int i = 0; i < 10; i++){
    arr[i] = i;
}

for(int i = 0; i < 10; i++){
    cout << arr[i] << "\n";    
}


こんな感じで出力されると思います。

以上で競プロ特化型C++まとめは終了です。お疲れ様でした!

まとめ

この記事を通してC++で競プロに挑戦してみようかなと思っていただければ幸いです。今回は本当に必要な知識のみを紹介したので、B問題以降も挑戦してみたい!という方はC++をもう少し知る必要があります。以下の記事などを参考にして学習してみてください。
https://qiita.com/e869120/items/f1c6f98364d1443148b3

(よかったら私の記事もぜひw)
https://zenn.dev/somahc/articles/c8af71e617d5f5

お疲れ様でした!

おまけ - 実際の問題を解いてみよう

余力のある人は実際にC++を使って問題を解いてみましょう!例題はABC330のA問題です。
https://atcoder.jp/contests/abc330/tasks/abc330_a
考えてみて、もし回答ができたら提出してみてください!以下に今回学んだ内容全てを使った解法も用意してあるので、ぜひ見てみてください。

今回の内容を全て使った解法

方針

テストを受けた人数であるnと、合格点であるlをまずは標準入力で受け取ります。次に、n人の学生の点数を配列scoreに入れていきます。最後にscore配列の各要素を参照して、l以上であればカウント用の変数cntを+1することで、l点以上のスコアをとった学生の数がわかるはずです。
制約を見ると今回はnが最大でも100であることから、score配列のサイズは100あれば十分でしょう。

実装

#include <iostream>
#include <string>
using namespace std;

int main(){
    int n,l,score[100]; // 変数と配列を定義
    cin >> n >> l; // n, lの値を入力
    for(int i = 0; i < n; i++){ // 学生の数だけループ
        cin >> score[i]; // score配列にそれぞれの学生の点数を入力
    }

    int cnt = 0;
    for(int i = 0; i < n; i++){
        if(score[i] >= l) cnt++; // scoreがl以上ならcntを+1
    }

    cout << cnt << "\n"; // cntの値を出力して終了
    return 0;
}

なお、今回は勉強した内容を全て使うためちょっと回りくどい実装をしています。実際には配列を使わなくてもできる他、for文も1つで足ります。詳しくは公式の解説を確認してみてください!

GitHubで編集を提案

Discussion