バケット法 joi2010予選 d bit全探索 atcoder

JOI2010予選 D - カード並べ

JOI2010予選 D - カード並べ
Feb. 2, 2020, 1:52 p.m.

目次

問題

https://atcoder.jp/contests/joi2010yo/tasks/joi2010yo_d

入力

N
K
c_1
c_2
...
c_N
  • N - カードの枚数 ($4 \leq N \leq 10)
  • K - 選ぶ枚数 ($2 \leq K \leq 4)
  • c_i - カードに書かれた数字 ($1 \leq c_i \leq 99)

出力

N枚のカードからKを選んで自由に並び替えて出来る数字の数を答える問題です.
同じ数字が複数出来てもまとめて1と数えます.

入出力例

4
2
1
2
12
1
7

解説

単純に与えられたカードのすべての並べ方を試してみます.
そしてそこから先頭$K$個選んで数字を作ります.
それが初めて生成された数字ならカウントを+1していきます.
これですべてのカードの並べ方を試し終わった時カウントが答えになっているはずです.

すべてのカードの並べ方は$N!$通りです.
そしてK個選んだカードから数字を組み立てるためにはすべての数字をチェックする必要があるので計算量$O(K)$です.
合わせても$O(N! \cdot K)$なので間に合います.

計算量

実行時間: 52ms

$$
O(N! \cdot K)
$$

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#define MAX_N 10
#define MAX_K 4

Int N, K;
vector<Int> C;
// 2桁 x 4つ
vector<bool> bucket(pow(10, 9), false);

void input() {
  cin >> N >> K;
  Int _c;
  while (cin >> _c) C.push_back(_c);
}

Int buildInt() {
  Int n = C.at(0);
  loop(k,1,K) {
    if (C.at(k) >= 10) n *= 100;
    else n *= 10;
    n += C.at(k);
  }
  return n;
}

Int bit() {
  sort(span_all(C));
  Int counter = 0;
  Int n = 0;
  do {
    n = buildInt();
    if (!bucket.at(n)) {
      bucket.at(n) = true;
      counter++;
    }
  } while (next_permutation(span_all(C)));

  return counter;
}

void solve() {
  cout << bit() << endl;
}

int main(void) {
  input();
  solve();
  return 0;
}