사용한 알고리즘
알고리즘 설명
- 위에 조합에서 수식을 만들어 내기 위해서 예시를 들겠다.
ex 1. 1234 -> 2134 와 같이 앞자리 수가 변하기 위해서는 그 사이에 3!(n!)의 경우의 수가 존재한다.
ex 2. 4xxxx 인 경우 3*4! 의 경우의 수가 사이에 존재한다
ex 3. 45xxx 와 같은 경우 3*4!의 경우의 수가 기본적으로 존재하고 5 밑에는 1,2,3인 숫자 3개가 존재하므로 3*3! 가 필요하여 45xxx 에 대해서 3*4! + 3*3! 가 필요하다.
ex 4. 451xx와 같은 경우 숫자 1 이하에 숫자가 존재하지 않으므로 경우의 수 변화가 없다
ex 5. 4513x와 같은 경우 숫자 3 이하에 숫자 2가 존재하므로 1*1! 만큼 더하여 3*4! + 3*3! + 1*1!
ex 6. 45132와 같은 경우 숫자 2 이하에 숫자는 존재하지 않으므로 45132는 (3*4! + 3*3! + 1*1!) + 1번째 숫자이다.
- 위를 이용하여 역으로 이용하면 K번째 수도 추려낼 수 있다.
풀이
// baekjoon 1722 yechan
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX_N=21;
int N, cmd;
ll fact[MAX_N], K;
bool visited[MAX_N];
ll factorial(ll x) {
if (x == 0) return 1;
if (fact[x]) return fact[x];
return fact[x] = x*factorial(x-1);
}
int main() {
scanf("%d", &N);
scanf("%d", &cmd);
if (cmd == 1) {
scanf("%lld", &K);
K--;
for (int i=1; i<=N; i++) {
ll x = K/factorial(N-i);
for (int j=1; j<=N; j++) {
if (visited[j]) continue;
if (!x) {
visited[j]=true;
printf("%d ", j);
break;
}
x--;
}
K = K%factorial(N-i);
}
} else {
ll ret = 1;
for (int i=1; i<=N; i++) {
int x;
scanf("%d", &x);
visited[x]=true;
for (int j=1; j<x; j++)
if (!visited[j])
ret += factorial(N-i);
}
printf("%lld\n", ret);
}
return 0;
}