yutasの競技プログラミング勉強帖

競技プログラミングの問題についての解説記事を主に書いています。

A - Tricky Template / Educational Codeforces Round 161 (Rated for Div. 2)

問題

整数  n n 文字の英小文字からなる3つの文字列  a, \, b, \, c が与えられる。

また、  n 文字の英小文字と英大文字からなる文字列をテンプレートと呼ぶ。  1 から  n までのすべての  i について、以下の条件が成立するとき、文字列  s がテンプレート  t にマッチすると言う。

  • テンプレートの  i 番目の文字が小文字の場合、  {s}_{i} {t}_{i} が同じである。
  • テンプレートの  i 番目の文字が大文字の場合、  {s}_{i} {t}_{i} の小文字は同じではない。
    • 例えば、  {t}_{i} = A のとき、  {s}_{i}a 以外の文字でなければならない。

このとき、  a b のテンプレートであり、  c のテンプレートではない文字列が存在するかを判定せよ。

入力

まず最初の1行目に、テストケースの個数を表す整数  t が与えられる。

その後、 t 個のテストケースのそれぞれに対して、以下のように入力が与えられる。

  • 最初の1行目には、整数  n が与えられる。
  • その後3行に渡り、文字列  a, \, b, \, c がそれぞれ1行ずつで与えられる。

条件

  • 実行時間制限: 2s
  • メモリ制限: 256MB
  •  1 \leq t \leq 1000
  •  1 \leq n \leq 20

出力

 t 行に渡り、各テストケースについて、テンプレートが存在する場合は YES を、存在しない場合は NO を出力すること。

解法

まず、与えられる2つの文字列  a, \, b のテンプレートとなる文字列は必ず存在します。 これは、そのテンプレートとなる文字列を  t とすると、 1 \leq i \leq n である  i について、

  •  {a}_{i} = {b}_{i} であるならば、  {t}_{i} = {a}_{i} \, ( = {b}_{i} ) とすることにより、条件を満たす
  •  {a}_{i} \ne {b}_{i} であるならば、  {t}_{i} {a}_{i} の大文字、  {b}_{i} の大文字とは異なる大文字を配置することにより、条件を満たす

という方法をすべての  i に対して行えばテンプレートが完成するためです。

さて、テンプレートとなるための条件は  1 文字目から  n 文字目までのすべての文字について、与えられた条件を満たすことになります。 従って、逆に与えられた条件を満たさないような箇所が1箇所でもあると、テンプレートとはなりません。

以上から、  a, \, b のテンプレートであって、  c のテンプレートではない文字列が存在すると仮定して、これを  t とします。 このときに、  t i 番目の文字によって、  t c のテンプレートではないと判断できるとすると、

  •  {a}_{i} = {b}_{i} であるならば、  {t}_{i} は小文字であるため、  {c}_{i} \ne {t}_{i} ならば  t c のテンプレートでなくなる
    • このとき、  {t}_{i} = {a}_{i} = {b}_{i} であるため、  {a}_{i} \ne {c}_{i} かつ  {b}_{i} \ne {c}_{i} が成立する
  •  {a}_{i} \ne {b}_{i} であるならば、  {t}_{i} は大文字であるため、  {t}_{i} {c}_{i} の大文字であれば、  t c のテンプレートでなくなる
    • このとき、  t が存在する仮定なので、  {t}_{i} {a}_{i} の大文字と  {b}_{i} の大文字であってはならない
    • 従って、  {a}_{i} \ne {c}_{i} かつ  {b}_{i} \ne {c}_{i} が成立する

というように条件を整理することができます。

従って、問題の条件を満たすような文字列が存在するための条件は、 [txe: {a}_{i} \ne {c}_{i}] かつ  {b}_{i} \ne {c}_{i} を満たすような  i が少なくとも1つは存在すること、ということになります。

これは、  O(n) の計算量で求めることができるので、実行時間制限にも十分間に合うと言えます。

ソースコード

各テストケースに対して、テンプレートが存在する場合は true を、存在しない場合は false を返す関数 solve() を以下のように実装しました。

int n;
string s[3]; // 3つの文字列が入る配列

bool solve() {
  // 値の入力
  cin >> n;
  for (int i = 0; i < 3; i++) {
    cin >> s[i];
  }

  for (int i = 0; i < n; i++) {
    // 上記条件が1つでも満たされていればテンプレートは存在するので、 true を返す
    if (s[0][i] != s[2][i] && s[1][i] != s[2][i]) {
      return true;
    }
  }

  return false;
}

感想

最初問題文を原文のまま見たときに、何を判断させる問題なのかわかりませんでした。 自身の英語力を鍛えないといけないですね…。