ponpon57
@ponpon57 (Pon 57)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

AtCoder232 B

以下のコードはAtCoder過去問232のB問題公式解説です。
//s2[i] = ((s2[i]-'a')+k)%26 + 'a';//
この部分が理解できません
kはintegerでなぜ文字列s2などの(s2[i]-'a')と足せるのか、-'a'と+'a'の違いがなんなのか。調べてもよくわからなかったので、どなたか解説お願いします。

問題文
高橋君は英小文字からなる文字列 S を持っています。

高橋君は文字列 S に対して、下記の操作をちょうど 1 回行います。

まず、非負整数 K を選ぶ。
その後、S の各文字を K 個後ろの英小文字に変更する。
ただし、

a の 1 個後ろの英小文字は b であり、
b の 1 個後ろの英小文字は c であり、
c の 1 個後ろの英小文字は d であり、
⋯
y の 1 個後ろの英小文字は z であり、
z の 1 個後ろの英小文字は a です。
例えば、b の 4 個後ろの英小文字は f であり、y の 3 個後ろの英小文字は b です。

文字列 T が与えられます。 高橋君が上記の操作によって S を T に一致させることができるかを判定してください。

制約
S と T はそれぞれ英小文字からなる長さ 1 以上 10 
5
  以下の文字列
S の長さと T の長さは等しい
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
  string s, t;
  cin >> s >> t;
  
  for(int k = 0; k <= 25; k++){
    string s2 = s;
    for(int i = 0; i < (int)s.size(); i++){
      s2[i] = ((s2[i]-'a')+k)%26 + 'a'; //わからない
    }
    if(s2 == t){
      cout << "Yes" << endl;
      return 0;
    }
  }
  cout << "No" << endl;
  
  return 0;
}
0

1Answer

kはintegerでなぜ文字列s2などの(s2[i]-'a')と足せるのか

s2は文字列(string)ですが,s2[i]は文字(char)です.また,シングルクォーテーション'で囲まれたものも文字です.
コンピュータは文字も数字で扱います.ここでは1バイト文字であるcharもASCIIコード表に準じて数字が割り振られています.

alphabet a b c ... x y z
10進数 97 98 99 ... 120 121 122
16進数 61 62 63 ... 78 79 7A
ALPHABET A B C ... X Y Z
10進数 65 66 67 ... 88 89 90
16進数 41 42 43 ... 58 59 5A

もしs2[i]'a'であれば,実際に行われている演算は

s2[i] = (('a' - 'a') + k) % 26 + 'a';
s2[i] = (( 97 -  97) + k) % 26 +  97;

になります.文字s2[i]'a'で引くことにより,以下のように書けます.

s2[i] a b c ... m n o ... x y z
s2[i] - 'a' 0 1 2 ... 12 13 14 ... 23 24 25

アルファベットを0から始まる数字に変換することができました.
こうすることにより,アルファベットの個数26で割った余りを使うことができるようになります.
なぜなら26で割った余りは0から25までの数字であり,これをアルファベットのaからzに割り当てて考えることができるからです.
その上で,式の前半部分でkを変化させた順に演算結果を見てみましょう.

s2[i] a b c ... m n o ... x y z
(s2[i] - 'a' + 0) % 26 0 1 2 ... 12 13 14 ... 23 24 25
(s2[i] - 'a' + 1) % 26 1 2 3 ... 13 14 15 ... 24 25 0
(s2[i] - 'a' + 2) % 26 2 3 4 ... 14 15 16 ... 25 0 1
... ...
(s2[i] - 'a' + 12) % 26 12 13 14 ... 24 25 0 ... 9 10 11
(s2[i] - 'a' + 13) % 26 13 14 15 ... 25 0 1 ... 10 11 12
(s2[i] - 'a' + 14) % 26 14 15 16 ... 0 1 2 ... 11 12 13
... ...
(s2[i] - 'a' + 23) % 26 23 24 25 ... 9 10 11 ... 20 21 22
(s2[i] - 'a' + 24) % 26 24 25 0 ... 10 11 12 ... 21 22 23
(s2[i] - 'a' + 25) % 26 25 0 1 ... 11 12 13 ... 22 23 24

s2[i] - 'a'からkを足して26で割った余りは,アルファベットをk個後ろにずらすという意味になることがわかると思います.ただし,このままの数字はaからzを0から25で表しただけです.最後に'a'すなわち97を足してあげることで,ASCIIコードの値に戻してあげることになり,コンピュータはアルファベットとして表示してくれます.

類題としてABC146-Bが挙げられます.今回は,これより1つ難易度が上がったものだと考えても良いでしょう.

1Like

Comments

  1. @ponpon57

    Questioner

    非常にわかりやすく説明していただきありがとうございます。理解できました!
  2. よかったです!
    ABC146-Bも解いてみてくださいね.

Your answer might help someone💌