【第1回】はじめてのAtCoderとC++

演算や変数、標準入出力などのC++の文法とAtCoderの使い方を学びます。

Homeブログ一覧【第1回】はじめてのAtCoderとC++

AtCoder アカウントを作成しよう

必要な情報を入力して、アカウントを作成しましょう。 ユーザー名は一度しか変更できないので、しっかり考えて決めましょう。 AtCoder アカウントの複数所持は禁止されています。すでに持っている人は飛ばしてください。

今回はAtCoder Beginners Selectionの問題を解きながら c++に慣れて行きます。 適宜、APG4bを参照してください。

PracticeA - Welcome to AtCoder

問題

整数 a,b,ca, b, c と文字列 ss が与えられるので、 a+b+ca + b + css を並べて出力しなさい。

制約

  • 1a,b,c1001 \le a, b, c \le 100
  • 1s1001 \le |s| \le 100

解くのに必要な知識

  • 入力
  • 出力
    • int
    • long long
    • double
    • string
  • 変数の扱い方
  • 四則演算
  • 文の最後にはセミコロンをつける

入力

入力は以下のように行います:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a, b;
    cin >> a >> b;  // a,bに入力を代入
}
  • cin >> a; で整数が 1 つだけ入力されます。今回はcin >> a >> b;としていて、この場合は 2 つの整数がそれぞれ変数 a, b に格納されます。
  • 1 行目と 2 行目はおまじないなので、今は気にしなくていいです。

出力

出力は以下のように行います:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a;
    cin >> a;
    cout << a;  // 変数aの値を出力
    cout << a << endl;  // aの出力後に改行を含める場合
}
  • cout << (出力したい値や変数) << endl; で出力がされます。
  • endlは改行を表します。

扱えるもの
int10910^9 までの整数を扱える ( 2312311-2^{31} \sim 2^{31}-1 まで OK)
long long101810^{18} までの整数を扱える ( 2632631-2^{63} \sim 2^{63}-1 まで OK)
double±1.7×10308\pm 1.7 \times 10^{308} までの実数を扱える
string文字列
  • intlong longの違いは、扱える範囲の広さです。
  • これらは、表せる値の範囲を超えるとオーバーフローします。

変数

  • 変数は<データの型> <変数名>;と記述して宣言します。
  • ,(カンマ) で区切ると、複数の変数を宣言することもできます。
  • 変数宣言後の、最初の値の代入を初期化といいます。
  • 初期化のタイミングは、変数宣言時と代入時のどちらでも構いません。
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a, b, c = 10;   // 最後に宣言されたcのみが、整数値10で初期化される
    b = 1;
    cout << a << endl;  // aは初期化されていないので、何が出力されるかはわからない
    cout << b + c << endl;
}

変数名には命名規則があり、以下の要件を満たさなければなりません:

  • アルファベット、数字、アンダースコア(_)のみ使用可能
  • 数字から始まる変数名は使用できない
  • 予約語は使用できない

四則演算

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a = 1, b = 2;
    cout << a + b << endl;  // 和 3
    cout << a - b << endl;  // 差 -1
    cout << a * b << endl;  // 積 2
    cout << a / b << endl;  // 商 0 (a, bはint型なので、小数点以下は切り捨てられる)
    cout << a % b << endl;  // 剰余 1
}

以上のことがわかれば、問題を解くことができます。

解答例

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a, b, c;  // 変数宣言
    string s;  // 変数宣言
    cin >> a >> b >> c >> s;  // 入力
    cout << a + b + c << " " << s << endl;
}

類題

ABC086A - Product

問題

a,ba, b の積が偶数か奇数かを判定するプログラムを書いてください。

制約

  • 1a,b1001 \le a,b \le 100
  • a,ba,bは整数

解くのに必要な知識

  • if 文
  • 比較演算子、論理演算子

if 文

意味
if条件が正しかった時だけ実行される
else条件が正しくなかった時実行される
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a;
    cin >> a;
    if (a > 0) {
        cout << "aは正の数です" << endl;
    } else if (a < 0) {
        cout << "aは負の数です" << endl;
    } else {
        cout << "aは0です" << endl;
    }
}
  • if文の条件式は、bool型の値を返す式でなければなりません。

比較演算子

  • !=,<=,>=は全部=が左にあります
演算子意味
x == yx, y は等しい
x != yx, y は等しくない
x > yy より x は大きい
x < yy より x 小さい
x >= yx は y 以上
x <= yx は y 以下

論理演算子

演算子意味真になるとき
!(条件式)否定条件式が偽
(条件式 1) && (条件式 2)かつ条件式 1 と条件式 2 がともに真
(条件式 1) || (条件式 2)または条件式 1 と条件式 2 のどちらかが真

xy!xx && yx || y
00100
01101
10001
11011

以上のことが分かれば、B 問題を解くことができます。

解答例

  • a,b の積を 2 で割った余りが 0 なら偶数、1 なら奇数であることを利用
  • 文字列を出力するときは、"(ダブルクオーテーション)で囲む
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a, b, c;
    cin >> a >> b;
    c = a * b;
    if (c % 2 == 0) {  // cを2で割った余りが0なら偶数
        cout << "Even" << endl;
    } else {
        cout << "Odd" << endl;
    }
}

ABC081A - Placing Marbles

問題

文字列ssのうち、1 の個数を出力してください。

制約

ssは 3 文字の文字列で、'1' または '0'のみからなる

解くのに必要な知識

文字列(string)の扱い方

string型(文字列)の変数sに対して、以下のような処理ができます:

処理記法
文字列の長さの取得s.size()
文字列の取得s.at(i) または s[i]

添え字は 0 から数え始めることに注意してください!

  • 1 文字目 \rightarrow s[0]
  • 2 文字目 \rightarrow s[1]
  • n 文字目 \rightarrow s[n - 1]
#include <bits/stdc++.h>
using namespace std;

int main() {
    string s = "abcde", t = "fghij";
    cout << s.size() << endl;  // 5
    cout << s[0] << " " << s.at(0) << endl;  // a a  (どちらもaが出力される)
    s = s + t;  // sにtを連結
    cout << s << endl;  // abcdefghij 
}

文字(char)の扱い方

  • char型は 1 文字だけを表す型です。
  • 文字列は"(ダブルクオーテーション)で囲みますが、文字は'(シングルクオーテーション)で囲んで表現します。
#include <bits/stdc++.h>
using namespace std;

int main() {
    char c = 'a'; // "a" ではない
    cout << c << endl;  // a
}

複合代入演算子

演算子意味
x += yx = x+y
x -= yx = x-y
x *= yx = x \ y
x /= yx = x / y
x %= yx = x % y
x++x = x + 1
x--x = x - 1

以上のことが分かれば、問題を解くことができます。

解答例

#include <bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    int ans = 0;
    if (s[0] == '1') ans += 1;  // ans++;でもいい
    if (s[1] == '1') ans += 1;
    if (s[2] == '1') ans += 1;
    cout << ans << endl;
}

ABC081B Shift only

問題

NN個の正の整数a1,a2,...,aNa_1, a_2, ..., a_Nが与えられます。これらの整数のうち、偶数であるものはすべて 2 で割ったものに置き換えてください。このとき、操作を行った回数の最小値を求めてください。

制約

  • 1N2001 \le N \le 200
  • 1ai1091 \le a_i \le 10^9

解くのに必要な知識

for 文 while 文 配列

for 文

for文は、繰り返し処理を行うための文です。

for (初期化式; 条件式; 変化式){
    //繰り返し処理
}
#include <bits/stdc++.h>
using namespace std;

int main() {
    for(int i = 0; i < 3; i++) {  // iが3未満の間繰り返す
        cout << "hello" << i << endl;
        if (i == 1) break;  // iが1になったらfor文を抜ける
    }
}
#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int i = 0; i < 3; i++) {  // iが3未満の間繰り返す
        if (i == 1) continue;  // iが1になったら以降の処理をスキップして次の繰り返しに移る
        cout << "hello " << i << endl;
    }
}

while 文

while文は、条件式がtrueの間、繰り返し処理を行うための文です。

while (条件式) {
    //繰り返し処理
}
#include <bits/stdc++.h>
using namespace std;

int main() {
    int i = 0;
    while (i < 3) {  // iが3未満の間繰り返す
        cout << "hello world " << i << endl;
        i++;  // iを1増やす
    }
}

配列

配列は、同じ型の変数を複数まとめて扱うためのデータ構造です。C++ではvector型を用いて表現される事が多いです。

vector配列はvector<型名> n(要素数, 初期値);とすることで宣言できます。

vector配列vecに対して、以下のような操作ができます:

配列の操作記法
配列の要素数を取得するvec.size()
配列の要素を取得するvec.at(i) または vec[i]
配列の末尾に要素を追加するvec.push_back(x)
配列の末尾の要素を削除するvec.pop_back()

for 文を使って配列を走査する

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> vec;  // int型の配列vecを宣言
    vec = {1,2,3,4,5};  // 配列に値を代入
    cout << vec[0] << endl;  // 配列の0番目の要素を出力
    cout << vec.size() << endl;  // 配列の要素数を出力

    vector<long long> vec2(5, -1);  // 要素数5のlong long型の配列vec2を宣言して、すべての要素を-1で初期化
    for (int i = 0; i < 5; i++) cin >> vec2[i];  // 配列の要素を入力

    vec2.push_back(6);  // 配列の末尾に6を追加
    cout << vec2[5] << endl;  // 6 (配列の末尾の要素を出力)
}

これで、問題を解くことができます。

解答例

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];  // 配列の要素を入力

    int ans = 0;  // 操作を行った回数
    while (true) {  // 無限ループ
        for (int i = 0; i < n; i++) {  // 配列の要素を走査
            if (a[i] % 2 == 1) {  // 奇数の場合  a[i]%2!=0でもいい
                cout << ans << endl;  // 操作を行った回数を出力
                return 0;  // main関数を抜ける
            }
            a[i] /= 2;   // 偶数の場合、2で割る
        }
        ans++;   // 操作を行った回数を1増やす
    }
}

練習問題

まとめ

今回で APG4b の第 1 章の内容は大体終わりました。 練習問題もあるので解いてみてください。一回やっただけでは理解できないと思うので、何度もやってみてください。