백준문제풀이

백준 문제 1722번 순열의 순서 문제풀이 c++

노가다 김씨 2022. 3. 22. 15:38

https://www.acmicpc.net/problem/1722

 

1722번: 순열의 순서

첫째 줄에 N(1 ≤ N ≤ 20)이 주어진다. 둘째 줄의 첫 번째 수는 소문제 번호이다. 1인 경우 k(1 ≤ k ≤ N!)를 입력받고, 2인 경우 임의의 순열을 나타내는 N개의 수를 입력받는다. N개의 수에는 1부터 N

www.acmicpc.net

문제해석

 

이런 문제는 예시하나 들어서 규칙찾아내서 작성하는게 편한거같다.

케이스 2번부터보자.

4 2

3 2 1 4 가 입력이 주어졌을 경우를 예를들어보자.

 

처음에 작은 순서대로 1 2 3 4 가있고 3이 처음 수란것은 3!만큼 두번 움직였기때문에 3이나온것이다.

그래서 여기서 2*3!=12

 

3을 사용하였으니 그 다음 작은 순서대로 1 2 4 가있다.

2번째 수로 2란것은 2!만큼 한번 움직인 것이기 때문에 여기서 1*2!=2

 

이제 작은 순서대로 1 4가 있다.

3번째 수로 1이므로 1!만큼 0번 움직인 것이기 때문에 여기서 0*1!=0

 

마지막은 자동으로 넣으므로 계산하지않는다

12+2+0=14이고 14번째 순열 바로 다음 순열이 3 2 1 4인것이다.

따라서 3 2 1 4는 14+1=15번째 순열이 된다.

 

이제 이 방법을 역으로 생각해서 케이스 1번을 보자

4 1

15 가 입력으로 주어졌을 경우 예를 들어보자. 바로 위의 역이다.

먼저 15에서 1을 빼준다. 14가됨

 

14를 팩토리얼의 배수의 로 덧셈꼴 로 나타내면 끝난다.

팩토리얼의 배수란 x*y! (0<=x<=y) 이런형태이다. 

14를 이 형태로 나타내면 14=2*3!+1*2!+0*1! 이 되고 

3!에 곱해진수가 2란뜻은 1 2 3 4 중에서 (2+1)번째로 작은 수를 출력하란 뜻이 된다.

1 2 3 4중 3번째로 작은수는 3 남은수는 1 2 4

이 같은 방식으로 1 2 4중 (1+1)번째로 작은 수는 2 남은수는 1 4

1 4중 (0+1)번째로 작은수는 1 

마지막은 자동으로 4 

따라서 3 2 1 4가 답이된다.

 

이 과정을 바탕으로 코드를 작성하였는데 좀 복잡하게 짠듯한 느낌이든다.

작은 순서대로 계속 정렬하는것이 귀찮기 때문에 set내에서 자동정렬해주기때문에 set자료 구조를 사용하였다.

 

코드

 

#include <iostream>
#include <vector>
#include <set>
#include <string>
typedef long long int ll;
using namespace std;
void case1(ll n);
void case2(ll n);
ll check(ll n);
set <ll> s;
vector <ll> v;
ll ftr[21];
ll a[21];
int main(){
	cout.tie(NULL);
    cin.tie(NULL);
    ios_base::sync_with_stdio(false);
    ftr[0]=1;
    for(ll i=1; i<21; i++)
    {
        ftr[i]=i*ftr[i-1];
    }
    ll n,input;
    cin>>n>>input;
    for(ll i=1; i<=n; i++)
    {
        s.insert(i);
    }
    if(input==1)
    {
        case1(n);
    }
    else if(input==2)
    {
        case2(n);
    }
}
void case1(ll n){
    ll k;
    cin>>k;
    k--;
    ll index=check(k);
    for(ll i=0; i<n-1-index; i++)
    {
        v.push_back(*s.begin());
        s.erase(s.begin());
    }
    while(k>0)
    {
        index=check(k);

        n=n-index;
        auto iter=s.begin();
        for(ll i=0; i<k/ftr[index]; i++)
        {
            iter++;
        }
        v.push_back(*iter);
        s.erase(iter);
        k=k-ftr[index]*(k/ftr[index]);
        ll after=check(k);
        for(ll i=index; i>1+after; i--)
        {
            v.push_back(*s.begin());
            s.erase(s.begin());
        }
    }
    for(auto iter=s.begin(); iter!=s.end(); iter++)
    {
        v.push_back(*iter);
    }
    for(ll i=0; i<v.size(); i++)
    {
        cout<<v[i]<<" ";
    }
}
void case2(ll n){
    for(ll i=1; i<=n; i++)
    {
        cin>>a[i];
    }
    ll ans=0;
    for(ll i=1; i<=n; i++)
    {
        auto iter2=s.find(a[i]);
        ll cnt=0;
        for(auto iter=s.begin(); iter!=s.end(); iter++)
        {
            if(*iter==*iter2)
            {
                s.erase(iter);
                break;
            }
            else
            {
                cnt++;
            }
        }
        ans=ans+cnt*ftr[s.size()];
    }
    ans++;
    cout<<ans;
}
ll check(ll n){
    for(ll i=1; i<21; i++)
    {
        if(ftr[i]<=n&&n<ftr[i+1])
        {
            return i;
        }
    }
}