본문 바로가기

알고리즘/SWEA

8501

#define MOD 1000000007

static int N;
static int table[1001];

static void table_init()
{
	long long cur = 0;
	long long factorial = 1;

	for (int i = 1; i <= 1000; i++)
	{
		cur = i * cur;
		cur += (i / 2) * factorial;
		cur %= MOD;

		table[i] = (int)cur;
		factorial *= i;
		factorial %= MOD;
	}
}

문제의 답을 구하기 위한 점화식은 아래와 같다.

 

f(0) = 0, n >= 1 에 대해서

f(n) = n * f(n - 1) + [n / 2] * (n - 1)!

 

이와 같이 식을 세운 이유는 아래와 같다.

 

먼저 N = 4에 대해서 4를 놓는 위치에 대해 생각해보자. (x, y, z 는 1 ~ 3 중 중복되지 않는 하나의 값)

 

4 x y x

x 4 y z

x y 4 z

x y z 4

 

첫번째 경우에 대해서 4는 절대 뒤집히지 않는다.

case1 == f(3)

 

두번째 경우에서 4는 한번 뒤집힌다. 

case2 == f(3) + 3!

여기서 3!이 더해지는 이유는 다음과 같다.

N = 3 일 때 나열하는 모든 경우는 3! = 6 이다. 
여기에서는 뒤집힌 동전이 없는 경우, 1개인 경우, 2개인 경우가 있고, 이 모든 경우들에 4가 뒤집혔기 때문에 1을 각각 더해주어야 한다. 

그래서 총 3!이 더해지는 것과 같은 것이다.

 

세번째, 네번째 경우도 이와 같은 방식으로 그 경우의 수를 구할 수 있다.

 

이제 이를 수식으로 정리해보면 다음과 같이 구할 수 있다.

 

f(n) --> f(n-1) + {f(n-1) + (n-1)!} + f(n-1) + {f(n-1) + (n-1)!} ... + f(n-1) + {f(n-1) + (n-1)!}   n == even

     --> f(n-1) + {f(n-1) + (n-1)!} + f(n-1) + {f(n-1) + (n-1)!} ... + f(n-1)                           n == odd

     =  f(n) = n * f(n - 1) + [n / 2] * (n - 1)!

 

[n / 2] 는 int형 나눗셈으로 구할 수 있기 때문에 코드에서는 단순 나누기 2로 처리 할 수 있다.

또, f(n)은 최대 10억 6이 될 수 있고, f(n + 1)을 구할 때, n >= 4 이상만 되어도 오버플로우가 발생한다.

그래서 먼저 long long 형에 저장하는 것이다.

팩토리얼을 구하는 것도 마찬가지이다.

 

'알고리즘 > SWEA' 카테고리의 다른 글

8556  (0) 2021.11.08
2382  (0) 2021.11.08
2383  (0) 2021.11.04
8458  (0) 2021.11.04
8500  (0) 2021.11.04