BOJ 1722 - 순열의 순서 문제를 해결하는 방법을 설명한다.

  • 길이 NN의 순열의 KK 번째 순열을 구하는 것
  • 길이 NN의 순열이 주어졌을 때 그것이 몇 번째인지를 구하는 것

은 간혹 DP문제에서도 인덱스를 치환하는 것이 쓰이며, 꽤나 요긴한 팁라고 할 수 있다.

순열이 몇 번째인지 구하기Permalink

길이가 N=5N=5이라고 하자.

1,2,3,4,51,2,3,4,5 같은 순열은 11번 째 순열이다.

정의를 깔끔하게 하기 위해 KK번 째 수열이라고 하지 않고 K1K-1개를 skip한 후의 수열이라고 부르자.

수열이 3,x,x,x,x3,x,x,x,x 처럼 되어있다고 하자.

그럼 1,x,x,x,x or 2,x,x,x,x1,x,x,x,x~or~2,x,x,x,x 같은 순서를 이미 skip했다는 것이고, 그런 순열의 개수는 4!4! 이 두 번 곱해져서 24!2\cdot 4! 임을 알 수 있다.

따라서 이걸 정답에 더해준다.

그런데 이것이 첫 번째 인덱스가 아니고,

y,3,x,x,xy,3,x,x,x 같은 경우라고 해보자.

yy 는 이미 정해진 값이다. 원래 순열이 주어져있으므로 정해져 있는건 맞지만 저 자리에 y+1y+1 이상이면 KK 보다 많이 skip 해야하기 때문에 다음 인덱스(i=0i=1)(i=0 \to i=1)를 검사하기 시작했다는 뜻이다.

그럼 xx 중에서 33 보다 작은 수의 개수를 세야한다. 아직 안 사용한 수를 보면 3,x,x,x3,x,x,x 뿐이고, 여기서 33 보다 작은 것의 개수가 길이 3짜리 순열을 skip한 개수이다.

따라서 x중에서 3보다 작은 x의 개수3!x\text{중에서 3보다 작은 } x\text{의 개수} \cdot 3! 을 정답에 더해준다.

이런식으로 모든 인덱스를 순회하면 몇개를 skip한 순열인지 구해진다.

따라서 순열의 순서는 구해진 정답(skip한 개수)에 1을 더해주면 된다.

vi a(n);  
fv(a);  
  
// 몇 번째 순열인지 찾는다.  
int ans = 0;  
for (int i = 0; i < n; i++) {  
   int less = 0;  
   for (int j = i + 1; j < n; j++) if (a[j] < a[i]) less++;  
   ans += fac[n - 1 - i] * less;  
}  
cout << ans + 1;

KK 번째 순열 구하기Permalink

또 팩토리얼을 이용하면 된다.

여기서는 이제 지금까지 안 쓴 값을 배열로 직접 관리한다. 이걸 remain 이라고 하자.

KKKK1K \coloneqq K-1 을 해준다. 왜냐면 KK 번 째를 구하는게 아닌 KK 개를 스킵한 후의 결과를 구하기 위함이다.

처음엔 11부터 NN까지 모두 넣어두고, 처음 자리에 뭐가 들어가야할 지 구한다고 해보자.

지금까지 안 쓴 수중에 K(N1)!\left\lfloor\dfrac K{(N-1)!}\right\rfloor 개를 스킵할 수 있으므로,

remain[K(N1)!]remain\left[\left\lfloor \dfrac K{(N-1)!} \right\rfloor\right] 를 이번에 써야 할 수로 정해주고 remainremain 에서 그 수를 지워주면 된다.

이후 KK 는 그만큼 skip한 것이므로 K(N1)!(N1)!\left\lfloor \dfrac K{(N-1)!} \right\rfloor\cdot (N-1)! 만큼 빼줄 수 있다.

0!=10!=1 이므로 denominator=0 이 될 일은 없다.

int k;  
cin >> k;  
k--;  
  
// k 번째 순열을 찾는다.  
vi remain(n);  
iota(all(remain), 1);  
vi ans;  
for (int i = 0; i < n; i++) {  
   int f = fac[n - 1 - i];  
   ans.pb(remain[k / f]);  
   k -= k / f * f;  
   remain.erase(find(all(remain), ans.back()));  
}  
for (int i: ans) cout << i << ' ';

Tags:

Categories:

Updated:

Comments