1. 문제
9375번: 패션왕 신해빈
첫 번째 테스트 케이스는 headgear에 해당하는 의상이 hat, turban이며 eyewear에 해당하는 의상이 sunglasses이므로 (hat), (turban), (sunglasses), (hat,sunglasses), (turban,sunglasses)로 총 5가지 이다.
www.acmicpc.net
2. 풀이
경우의 수가 바로 안나오기는 한디... 경우를 나눠서 생각해보면
hat headgear
sunglasses eyewear
turban headgear
headgear에 2가지 있고 eyewear에 1가지 있는데..
headgear에서 1가지를 뽑는 경우의 수 = 2가지 + eyewear에서 1가지 뽑는 경우의 수 1가지 = 3가지
headgear에서 1가지, eyewear에서 1가지 뽑는 경우의 수 = 2*1 = 2가지
= 총 3+2 = 5가지
사실 조금 생각해보면.. 옷의 각 종류별로 a1,a2,a3...,an이 있다고 할때 집합 {a1,a2,...,an}의 모든 부분집합
{a1}, {a2}, ... {a1,a2,...,an}의 원소들의 곱의 합이 정답이다.
위 경우도 {1,2}의 부분집합 {1}, {2}, {1,2}의 원소들의 곱의 합 1 + 2 + 1*2 = 5가 된다
근데 부분집합 구하는 법이 생각 안나서..
https://deepdata.tistory.com/428
바이너리 카운팅을 이용한 부분집합 구현과 재귀함수를 이용한 조합 구현하기
1. 부분집합 생성하기 비트 연산 1
deepdata.tistory.com
찾아봐서 부분집합 구해서 원소들의 곱의 합 구해도... 시간초과더라
당연한게 최대 30가지니까 최악의 경우 2^30 = 약 10억 정도라 1초안에 될리가 없지
from sys import stdin
T = int(stdin.readline())
for _ in range(T):
n = int(stdin.readline())
clothes = {}
for _ in range(n):
a,b = stdin.readline().rstrip().split()
clothes[b] = clothes.get(b,0) + 1
answer = 0
all = list(clothes.keys())
m = len(all)
for i in range(1 << m):
partial = []
for j in range(m):
if i &(1 << j):
partial.append(all[j])
if len(partial) == 0:
continue
count = 1
for p in partial:
count *= clothes[p]
answer += count
print(answer)
3. 모든 부분집합의 원소들의 곱의 합
사실 다음과 같은 공식?이 있는데
{a1,a2,...,an}의 원소가 k개인 부분집합의 곱의 합을 Sk라고 한다면..
(x+a1)(x+a2)...(x+an)=xn+S1xn−1+...+Sn
수학적 귀납법으로 보일 수 있을 것 같기는 한디.. 간단하게 증명해보자면..
n = 1이면 S1=a1이므로 자명
자연수 k에 대하여 n = k에서 성립한다고 가정하면.. n = k+1에서 성립하는가?
(x+a1)..(x+ak)=xk+S1xk−1+...+Sk
양변에 x+ak+1을 곱하면..
(xk+S1xk−1+...+Sk)(x+ak+1)=xk+1+S1xk+...+Skx+ak+1xk+ak+1S1xk−1+...+ak+1Sk
xk+1+(S1+ak+1)xk+...+(S2+ak+1S1)xk−1+...+ak+1Sk
S1+ak+1=a1+...ak+ak+1=S1으로 원소가 1개인 부분집합의 원소들의 곱의 합
S2+ak+1S1=∑i≠jaiaj+∑i=k+1,j≠k+1aiaj=S2으로..
원소가 2개인 부분집합의 원소들의 곱의 합
...
ak+1Sk=ak+1a1a2...ak=Sk+1로 원소가 k+1개인 부분집합의 원소들의 곱의 합
그래서..
(xk+S1xk−1+...+Sk)(x+ak+1)=xk+1+S1xk+...+S2xk−1+...+Sk+1
그러므로 n = k+1에서도 성립한다
아무튼 위 사실에 입각하면 구하고자 하는 값은 S1+S2+...+Sn
x = 1을 대입해도 성립하는 항등식이므로.. (1+a1)(1+a2)...(1+an)=1+S1+...+Sn
그러므로 옷의 종류들의 개수 ai를 저장해두고, for문으로 순회하면서 1을 더한채로 누적곱을 한 다음
마지막에 1을 빼준다면 O(N)에 문제를 해결할 수 있을 것이다.
from sys import stdin
T = int(stdin.readline())
for _ in range(T):
n = int(stdin.readline())
clothes = {}
for _ in range(n):
a,b = stdin.readline().rstrip().split()
clothes[b] = clothes.get(b,0) + 1
answer = 1
for k,v in clothes.items():
answer *= (v+1)
print(answer - 1)
'알고리즘 > 확률론 알고리즘' 카테고리의 다른 글
주사위를 던져서 얻은 눈의 수의 합이 n이상이 되기 위해 던져야 하는 횟수의 기댓값 (0) | 2025.01.18 |
---|---|
확률론 - 5000!개의 거리의 합의 평균을 구하는 방법 (0) | 2023.06.03 |