※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 26079번 문제인 곰곰이와 하카타이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/26079
26079번: 곰곰이의 벼락치기
$(1, 2, 4, 3, 5), (1, 2, 4, 5, 3), (1, 2, 5, 4, 3)$으로 시청하는 3가지 방법이 존재한다.
www.acmicpc.net
먼저 봐야 하는 강의가 없는 강의는 "0번 강의"라는 가상의 강의를 먼저 봐야하는 것으로 취급하면, 각 1~N번 강의는 먼저봐야 하는 강의가 정확히 하나씩 정해져있으므로 이 관찰을 바탕으로 문제의 상황을 0을 루트로 갖는 트리로 모델링할 수 있다. 이 때, (루트를 제외한) 모든 각 노드에 대응되는 강의는 자신의 부모에 대응되는 강의를 먼저 본 뒤 볼 수 있다는 성질이 있음을 확인하자.
각 강의에 대하여, 강의 X를 루트로 갖는 서브트리에 대한 강의를 듣는 순서의 경우의 수는 각 자식을 루트로 갖는 서브트리에 대한 강의를 듣는 경우의 수들의 곱과, 각 자식의 서브트리에 속한 노드들을 서브트리별로 색을 구분해 칠했을 때 이 노드들을 색을 기준으로 나열하는 경우의 수를 곱하는 것으로 계산할 수 있다. 이를 이용해 문제를 해결하자.
아래는 제출한 소스코드이다.
#define MOD 1000000007
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
ll fact[200001];
ll invfact[200001];
void init() {
fact[0] = fact[1] = 1;
for (ll i = 2; i < 200001; i++) {
fact[i] = (fact[i - 1] * i) % MOD;
}
invfact[0] = invfact[1] = 1;
for (ll i = 2; i < 200001; i++) {
invfact[i] = MOD - ((MOD / i) * invfact[MOD % i]) % MOD;
}
for (int i = 2; i < 200001; i++) {
invfact[i] = (invfact[i] * invfact[i - 1]) % MOD;
}
}
int N, M;
int parent[200001];
vector<int> G[200001];
pair<ll, ll> dfs(int cur, int par) { // {경우의 수, cur을 루트로 갖는 subtree의 노드 개수}
ll ret = 1;
ll childcnt = 0;
for (auto& nxt : G[cur]) {
if (nxt == par) continue;
auto tmp = dfs(nxt, cur);
ret = (ret * tmp.first) % MOD;
ret = (ret * invfact[tmp.second]) % MOD;
childcnt += tmp.second;
}
ret = (ret * fact[childcnt]) % MOD;
return make_pair(ret, childcnt + 1);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
init();
cin >> N >> M;
while (M--) {
int x, y; cin >> x >> y;
parent[y] = x;
}
for (int i = 1; i <= N; i++) G[parent[i]].emplace_back(i);
cout << dfs(0, -1).first;
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 24395 // C++] 명진이의 신년계획 (0) | 2022.12.06 |
---|---|
[BOJ 24394 // C++] 123456789점 (0) | 2022.12.05 |
[BOJ 26078 // C++] 곰곰이와 토너먼트 (0) | 2022.12.04 |
[BOJ 24390 // C++] 또 전자레인지야? (0) | 2022.12.04 |
[BOJ 26027 // C++] Disc District (0) | 2022.12.03 |