【第3回】これまでの復習をしよう

第1/2回入門講習で学んだC++をAtCoderを使って復習しましょう。

Homeブログ一覧【第3回】これまでの復習をしよう

今回は過去の講習の復習をします。

ABC294: A - Filter

問題文

長さ NN の整数列 A=(A1, A2, ... , AN)A = (A_1,\ A_2,\ ...\ ,\ A_N) が与えられます。

AA から偶数だけすべて取り出し、もとの順番を保って出力してください。

制約

  • 1N1001 \leq N \leq 100
  • 1Ai100 (1iN)1 \leq A_i \leq 100\ (1 \leq i \leq N)
  • AA には1つ以上の偶数が含まれる
  • 入力はすべて整数

入力

入力は以下の形式で標準入力から与えられる。


NN
A1 A2 ... ANA_1\ A_2\ ...\ A_N


出力

AA から偶数を取り出した列を、空白区切りで1行に出力せよ。

ヒント

for文を使い、 A1, A2, ..., ANA_1,\ A_2,\ ...,\ A_N を順番に調べてみる。

解答例

簡易的なフローチャートと、実際のプログラムは以下の通りです。

true
true
false
false
Start
要素を配列Aに格納 < br > (要素数N)
i = 0
i < N
A[i]が偶数
A[i]を出力
i++
End
#include <bits/stdc++.h>
using namespace std;

int main() {
    int N; cin >> N;    // Nを受け取る

    vector<int> A(N);   // 長さNの配列を用意する

    // A_1, A_2, ..., A_NをAに格納する
    for (int i = 0; i < N; i++) cin >> A[i];

    for (int i = 0; i < N; i++) {
        // A[i]を2で割った余りが1なら(つまり奇数なら)飛ばす
        if (A[i] % 2) continue;

        cout << A[i] << " ";
    }

    cout << endl; // 最後に改行を出力する
}

repマクロを使用すると、もう少しコンパクトに書けます:

#include <bits/stdc++.h>
// #define ... の行を追加
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    int N; cin >> N;

    vector<int> A(N);
    rep(i, N) cin >> A[i];

    rep(i, N) {
        if (A[i] % 2) continue;
        cout << A[i] << " ";
    }
    cout << endl;
}

ABC293: A - Swap Odd and Even

問題文

英小文字からなる長さが偶数の文字列 SS が与えられます。

i=1, 2, ..., S2i = 1,\ 2,\ ...,\ \frac{|S|}{2} の順に以下の操作を行い、全ての操作を終えた後の SS を出力してください。

  • S2i1S_{2i-1}S2iS_{2i} を入れ替える

制約

  • SS は英小文字からなる長さが偶数の文字列
  • 1S1001 \leq |S| \leq 100 ( S|S| は文字列 SS の長さ)

入力

入力は以下の形式で標準入力から与えられる。


SS


出力

答えを出力せよ。

ヒント

  • 文字の入れ替えにはswap関数を用いる
  • 先頭の文字がS[0]に対応する
  • forループを回す際、 ii が0と1のどちらからカウントされるのかをしっかりと追う
    • i=0i = 0 のとき 2i1=12i - 1 = -1 になってしまう

解答例

S = "abcdef"のとき、 S2=3\frac{|S|}{2}= 3 です。問題で指示されている操作を図示すると、以下のようになります。

ただし、 i=0, 1, 2i = 0,\ 1,\ 2 であることに注意してください。

swap(S[0], S[1])
a
b
c
d
e
f
i = 0 (2i = 0, 2i + 1 = 1)
swap(S[2], S[3])
b
a
c
d
e
f
i = 1 (2i = 2, 2i + 1 = 3)
swap(S[4], S[5])
b
a
d
c
e
f
i = 2 (2i = 4, 2i + 1 = 5)
b
a
d
c
f
e
Result
  • i=1, 2, ..., S2i = 1,\ 2,\ ...,\ \frac{|S|}{2} に対して、 S2i1S_{2i-1}S2iS_{2i} を入れ替る
  • i=0, 1, ..., S21i = 0,\ 1,\ ...,\ \frac{|S|}{2} - 1 に対して、 S2iS_{2i}S2i+1S_{2i + 1} を入れ替る

これらの操作の違いは、 SS の1文字目を1から数えているか、あるいは0から数えているかということだけで、行っていることは変わりません。

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    string S; cin >> S;

    rep(i, S.size() / 2) swap(S[2 * i], S[2 * i + 1]);
}

ABC295: A - Probably English

問題文

英小文字からなる NN 個の文字列 W1, W2, ..., WNW_1,\ W_2,\ ...,\ W_N が与えられます。

これらのうち一つ以上がand, not, that, the, you のいずれかと一致するならYes 、そうでないならNoと出力してください。

制約

  • NN は1以上100以下の整数
  • 1Wi501 \leq |W_i| \leq 50
  • WiW_i は英小文字からなる

入力

入力は以下の形式で標準入力から与えられる。


NN
W1 W2 ... WNW_1\ W_2\ ...\ W_N


出力

答えを出力せよ。

ヒント

  • 文字列 W1, W2, ..., WNW_1,\ W_2,\ ...,\ W_N を受け取る処理は、vector<string>型である配列を作って、for文で受け取ることで実装できる
  • キーワードの配列を作っておくと、単語を検証する処理の実装が楽になる

解答例

この問題は、 NN 個の単語に対して5つの単語のどれかと合致するか判定することを繰り返す問題です。

for文の中にif文を5つ並べても実装できます:

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    // 入力の処理
    int N; cin >> N;

    bool has_keyword = false;

    rep(i, N) {
        // Wを受けとる
        string word; cin >> word;

        if (word == "and") has_keyword = true;
        if (word == "not") has_keyword = true;
        if (word == "that") has_keyword = true;
        if (word == "the") has_keyword = true;
        if (word == "you") has_keyword = true;
    }

    if (has_keyword)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
}

実は、もう少し簡単な方法として、「if文の中で変化するものだけを配列に入れてfor文を回す」というものがあります。

簡易的なフローチャートは以下の通りです:

true
false
true
false
Start
Nを受け取る
指定されているキーワードを < br > 配列keywordsに格納する
i = 0
i < N
文字列を受け取ってwordに格納
Noと出力
End
word in keywords
Yesと出力
i++
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    // 入力の処理
    int N; cin >> N;

    // キーワードの配列を作っておく
    vector<string> keywords = {
        "and", "not", "that", "the", "you"
    };

    rep(i, N) {
        // Wを受けとる
        string word; cin >> word;

        // wordがkeywordsに含まれているか検証したい
        // wordに対して、keywordsの5要素をチェック
        rep(j, keywords.size()) {
            if (word == keywords[j]) {
                cout << "Yes" << endl;
                return 0;   // プログラムを終了
            }
        }
    }
    // Yesと出力されなかったときにNoと出力する
    cout << "No" << endl;

}

また、範囲for(Range-based for)文を使うと、楽にコーディングできることがあります:

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    int N; cin >> N;

    vector<string> keywords = {
        "and", "not", "that", "the", "you"
    };

    rep(i, N) {
        string word; cin >> word;

        // 範囲for文を使ってみる
        // keywordsの要素が、前から1つずつkeywordに代入される
        for (string keyword : keywords) {
            if (word == keyword) {
                cout << "Yes" << endl;
                return 0;
            }
        }
    }

    cout << "No" << endl;

}

for (string keyword : keywords)と書くことにより、 keyword = "and", "not", "that", "the", "you"と代入されていきます。

ABC292: A - CAPS LOCK

問題文

英小文字のみからなる文字列 SS が与えられます。

SS の各文字を英大文字に変換して得られる文字列 TT を出力してください。

制約

  • SS は英小文字のみからなる、長さが1以上100以下の文字列

入力

入力は以下の形式で標準入力から与えられる。


SS


出力

TT を出力せよ。

ヒント

  • 文字列 SS の長さはS.size()で取得できます。
  • ある英小文字 cc (1文字)を英大文字に変換する処理は、C++ではtoupper関数を用いて以下のように書けます:
// Cにcを大文字に変換したものを代入
char C = toupper(c);
  • string型は足し算ができます
    • S += "abc"とすると、 SS の後ろに"abc"が追加されます
    • S += 'a'のように、1文字だけ(char型)追加することもできます

解答例

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    string S; cin >> S;

    string T = "";  // 文字列Tを用意し、中身を空に初期化する
    rep(i, S.size()) T += toupper(S[i]);

    cout << T << endl;
}

ABC291: A - camel Case

問題文

英大文字および英小文字からなる文字列 SS が与えられます。

ここで、 SS のうちちょうど1文字だけが英大文字であり、それ以外は全て英小文字です。

大文字が SS の先頭から何文字目に登場するか出力してください。

ただし、 SS の先頭の文字を1文字目とします。

入力

入力は以下の形式で標準入力から与えられる。


SS


出力

大文字が SS の先頭から何文字目に登場するかを、整数で出力せよ。

ヒント

  • ある文字 cc が英大文字であることは、isupper関数を使うことで判定できる:
char c = 'A';
bool is_upper = isupper(c); // true

解答例

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;

int main() {
    string S; cin >> S;

    rep(i, S.size()) {
        // S[i]が大文字なら、if文の中身が実行される
        if (isupper(S[i])) {
            // iは0から数え始めているので、出力用に1から数え始めるように変換する
            cout << i + 1 << endl;
            return 0;   // 出力したらプログラムを終了する
        }
    }
}