오늘의 꿀팁 : 출력 크기가 MOD 연산을 써야 할 정도로 매우 크다면 DP를 시도해볼것.
DP로 푸는 것 까지는 좋은데... 문제는 어떻게 적용할지이다. 여기서 많은 시간을 소비했었다.
우선, i번째 열까지 배열했을 때, 짝수 행의 개수가 j개인 경우를 DP[i][j]로 정의하자. i = 0일때, 즉 1 개수 리스트의 첫번째 값 one_list[0]을 배열했을 때, 0의 개수는 col - one_list[0]이 되고, 초기값 DP[0][col - one_list[0]]은 C (col, one_list[0])이 된다. 즉 0이 col - one_list[0]개, 1이 one_list[0]개 있을 때 숫자들간의 순서를 고려하지 않고 배열하는 경우의 수와 같다.
이제 다음을 생각해보자. DP[i][j]에선 짝수 행이 j개,홀수 행이 col - j개 존재한다. 또한 one_list[i+1]에는 1이 tot_num 개 존재한다고 가정하자.
1은 당연히 홀수, 0은 짝수이다. 따라서 짝수 개 행에 1을 더하면 홀수, 홀수 개 행에 1을 더하면 짝수가 된다.
여기서, 짝수 행에 배치하고자 하는 1이 현재 짝수행보다 크거나, 홀수 행에 배치하고자 하는 1이 현재 홀수 행보다 적은 예외상황을 반드시 제외하자. 모든 i에 대해 이를 반복하면 최종적으로 모든 1을 배치했을 때 모든 행이 짝수인 경우의 수가 도출된다.
또한, 조합 계산 역시 최대 n이 300이므로 엄청나게 큰 값이 도출된다. 이를 일일히 직접 계산하는것보다는, 이 역시 메모이제이션을 통하여 계산해나가는 것이 좋다.
combination : 조합값을 구하는 함수. 조합값은 조합의 성질을 이용해 재귀적으로 구할 수 있다. 이미 메모이제이션으로 알고 있는 값일 경우 그 값을 그대로 반환한다. 모드 연산에 주의하자.
count_1s : 초기 a 리스트의 각 열의 1의 개수를 저장하여 반환하는 함수이다.
make_dp : 앞서 풀이한 DP를 통해 모든 DP 리스트를 채우는 함수이다.
solve : 메인함수. count_1s로 생성한 1의 개수 리스트를 make_dp에 전달하고, 반환된 DP에서 정답값을 찾아 반환한다.
풀이 코드
import sys
sys.setrecursionlimit(10000000)
MOD = 10**7 + 19
comb_list = [[0]*301 for _ in range(301)]
def combination(n, r) :
if n == 1 or n == r or r == 0 :
return 1
if comb_list[n][r] :
return comb_list[n][r]
comb_list[n][r] = ( combination(n-1,r-1) % MOD + combination(n-1,r) % MOD ) % MOD
return comb_list[n][r]
def count_1s(a, col, row) :
result = list()
for i in range(row) :
cnt = 0
for j in range(col) :
cnt += a[j][i]
result.append(cnt)
return result
def make_dp(col, row, lst) :
dp = [[0]*(col+1) for _ in range(row)]
dp[0][col - lst[0]] = combination(col, lst[0])
for i in range(row-1) :
for j in range(col+1) :
if dp[i][j] :
tot_num = lst[i+1]
for k in range(min(tot_num, j)+1) :
if col - j < tot_num - k :
continue
even = j + tot_num - 2*k
dp[i+1][even] += ( dp[i][j] % MOD * combination(j, k) * combination(col-j, tot_num - k) ) % MOD
return dp
def solution(a):
col, row = len(a), len(a[0])
one_list = count_1s(a, col, row)
dp = make_dp(col, row, one_list)
return dp[-1][-1]