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

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

C - 三つ組の積 / 第13回 アルゴリズム実技検定 (PAST13)

問題

長さ  n の整数列  a = [ {a}_{1} , {a}_{2}, \cdots , {a}_{n}  ] が与えられる。

このとき、次の条件を満たす整数  x の個数を求めよ。

  •  {a}_{i} \times {a}_{j} \times {a}_{k} = x かつ  1 \leq i \lt j \lt k \leq n を満たす  i, j, k が存在する。

入力

まず最初の1行目に整数  n が与えられる。

次の1行に、 n 個の整数  {a}_{1} , {a}_{2}, \cdots , {a}_{n} が順に与えられる。

条件

  •  3 \leq n \leq 100
  •  1 \leq {a}_{i} \leq 100

出力

答えとなる個数を1行で出力すること。

解法

問題としては「整数  x の個数を求める」というものなので、単純に  i, j, k に関してforループを回して積を求め、求めた積が既出かどうかで判断を行い個数を数えるという方法で解くことができます。

3重のforループを回すため、  O({n}^{3}) の計算量がかかりますが、  n \leq 100 であるので、最大でも約  {10}^{6} 回程度の計算で済むことから、実行時間制限にも十分に間に合うと考えられます。

ソースコード

main() 関数の中に、直接答えを出力する部分を実装しました。

int n, a[105], ans = 0; // ans は答えとなる個数を表す
map<int, bool> used; // used は既に積の値があるかどうかを管理する map

int main() {
  // 値の入力
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }

  for (int i = 1; i <= n; i++) {
    for (int j = i + 1; j <= n; j++) { // i < j より、 j = i + 1 からループを回す
      for (int k = j + 1; k <= n; k++) { // j < k より、 k = j + 1 からループを回す
        int now = a[i] * a[j] * a[k];
        if (!used[now]) { // もし積の値として既出でないならば、答えとなる個数を1つ増やす
          used[now] = true;
          ans++;
        }
      }
    }
  }

  cout << ans << endl; // 答えの出力

  return 0;
}

感想

問題文の書き方的に、「  x が与えられてそれを満たす  i, j, k の値の個数を求めよ」という問題かと思ってしまいそうになりました。