けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 225 A - Distinct Strings (7Q, 灰色, 100 点)

これ結構難しいと思う! 数学 IA の「場合の数」をやると、よく出て来るやつですね。

問題概要

英小文字のみからなる長さ 3 の文字列  S が与えられます。

 S の各文字を並び替えて得られる文字列は、何種類ありますか?

解法

「3 個のものを並び替える場合の数」は、数学 IA だとよく出て来るやつですね。実は次の 3 パターンがあります。


  •  (a, a, a) のように、すべて同じものを並び替える方法
    • 1 通りです
  •  (a, a, b) (a, b, b) のように、2 種類のもので構成される場合に、それを並び替える方法
    • 3 通りです
  •  (a, b, c) のように、3 種類のもので構成されるとき、それを並び替える方法
    • 6 通りです

たとえば、 (a, a, b) を並び替える方法は、

 (a, a, b), (a, b, a), (b, a, a)

の 3 通りあります。 (a, b, c) を並び替える方法は、

 (a, b, c), (a, c, b), (b, a, c), (b, c, a), (c, a, b), (c, b, a)

6 通りあります。

問題に戻って

上記のことを踏まえると、今回の問題は次のことを判別する問題だと言えます。

  • 文字列  S が 1 種類の文字で成り立つとき:1 通り
  • 文字列  S が 2 種類の文字で成り立つとき:3 通り
  • 文字列  S が 3 種類の文字で成り立つとき:6 通り

判別の手順としては、「1 種類」「3 種類」を判別するのが楽なので、「2 種類」を判別する部分は else 文に押し付けるのが楽ですね。

コード

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

int main() {
    string S;
    cin >> S;
    if (S[0] == S[1] && S[1] == S[2])
        cout << 1 << endl;
    else if (S[0] != S[1] && S[1] != S[2] && S[2] != S[0])
        cout << 6 << endl;
    else
        cout << 3 << endl;
}

AtCoder ABC 224 A - Tires (8Q, 灰色, 100 点)

文字列を上手に使う練習

問題概要

末尾が "er" か "ist" であるような文字列  S (2 文字以上) が与えられます。

どちらであるかを判定してください。

解法

末尾が "er" であるかどうかを判定することにしよう。文字列 S の長さを N とするとき、

  • S の末尾の文字は S[N - 1]
  • S の末尾から 2 文字目の文字は S[N - 2]

であることから、末尾が "er" であるかどうかは、次のように判定できる。

if (S[N - 1] == 'r' && S[N - 2] == 'e')

コード

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

int main() {
    string S;
    cin >> S;
    int N = (int)S.size();
    if (S[N-1] == 'r'&& S[N-2] == 'e')
        cout << "er" << endl;
    else
        cout << "ist" << endl;
}

 

別解

与えられる文字列は末尾が "er" か "ist" であることが保証されているのだから、実は「末尾の文字が 'r' であるかどうか」のみを判定すれば OK

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

int main() {
    string S;
    cin >> S;
    if (S.back() == 'r')
        cout << "er" << endl;
    else
        cout << "ist" << endl;
}

AtCoder ABC 223 A - Exact Price (8Q, 灰色, 100 点)

えぐいコーナーケースに注意! でもサンプルにあるね。

問題概要

財布に  100 円玉が 1 枚以上入っています。

財布に入っている合計金額がちょうど  X 円であるようなことが、あり得るかどうかを判定してください。

制約

  •  0 \le X \le 1000

考えたこと

基本的には「 X が 100 の倍数ならば "Yes" (そうでなければ "No")」と考えればよいでしょう。

ただし、100 円玉が 1 枚以上あることに注意すると、 X \gt 0 であることに注意しましょう。よって、

  •  X \gt 0 かつ  X が 100 の倍数のとき:"Yes"
  • そうでないとき:"No"

と処理すればよいでしょう。

コード

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

int main() {
    int X;
    cin >> X;
    if (X > 0 && X % 100 == 0)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
}

AtCoder ABC 222 A - Four Digits (8Q, 灰色, 100 点)

色んな方法がある。C 言語では、 printf() 関数を用いるのが楽だと思われる。

問題概要

0 以上 9999 以下の整数  N が与えられます。

 N の先頭に必要なだけ 0 をつけ、4 桁の文字列にしたものを出力してください。

解法

C 言語であれば、整数値  N の前に、4 桁になるように 0-padding する操作は次のように書ける。

printf("%04d\n", N);

コード

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

int main() {
    int N;
    scanf("%d", &N);
    printf("%04d\n", N);
}

AtCoder ABC 221 A - Seismic magnitude scales (灰色, 100 点)

for 文を用いるのが楽だと思う。

問題概要

マグニチュード  A の地震は、マグニチュード  B の地震の何倍の強さか?

(1 上がると 32 倍となる)

制約

  •  3 \le B \le A \le 9

解法

 32 A - B 回かけた値を求めればよい (つまり  32^{A-B})。

これを求めるためには、関数 pow() を用いるか、for 文を用いればよい。具体的には、答えを格納する変数を res としたとき

  • 初期状態では res = 1 としておく
  • for 文を用いて、 A - B 回、res *= 32 とする

というようにすればよい。

コード

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

int main() {
    int A, B;
    cin >> A >> B;
    
    int res = 1;
    for (int i = 0; i < A - B; ++i) {
        res *= 32;
    }
    cout << res << endl;
}