3316. 동아리실 관리하기
Code Battle (`23 동계 대학생 S/W 알고리즘 특강 기초학습 문제)
본 게시글은 개인 학습 용도로 작성한 게시글입니다.
(문제 출처: SW Expert Academy)
- Day 2 주제가 비트 연산이었던 것이 큰 힌트가 되었다. 각 날짜별 동아리원 참석 여부는 비트 마스킹으로 비교하였다.
- 첫 번째 날 A가 열쇠를 들고있다는 사실을 몰라서 한참을 헤매었다. → 문제를 꼼꼼히 읽을 것.
- 첫 풀이 시도에서는 분할정복, 완전탐색 문제로서 접근했는데, 제한된 시・공간 복잡도를 만족시키지 못하였다.
- $O(15^N)$의 시간 복잡도로 TLE.
- memoization을 통한 성능 개선을 시도했으나, stack 메모리 영역 사용량이 최대 2MB로 MLE (RE).
- DP를 사용하는 $O(N)$인 새로운 풀이 방식을 떠올리고 처음부터 다시 구현하여 한 번에 통과.
- $i$번째 날에 어떠한 동아리원 조합으로 활동이 가능한지 여부는 $i-1$번째 날 동아리원 조합과(곂치는 부원이 있는지), 담당자의 출석여부로만 결정된다는 것이 포인트.
- 어떤 임의의 날에 조합 가능한 동아리원의 경우의 수는 최대 $15$개이다. (아무도 안나오는 경우를 제외하여 $2^4-1$)
- $i=1…n$ 번째 날까지 순차적으로 계산해 나아간다면, $O(15^2n)$의 시간에 모든 날짜별 활동 가능한 경우의 수를 구할 수 있음.
#include <array>
#include <iostream>
#include <numeric>
#define MOD 1000000007
using namespace std;
void swapArray(array<int, 16>* x, array<int, 16>* y) {
array<int, 16> z;
z = *x;
*x = *y;
*y = z;
}
int solveTestCase(string assignees) {
int answer;
unsigned int day;
unsigned char assignee;
unsigned char member;
unsigned char lastMember;
array<int, 16> members;
array<int, 16> lastMembers;
lastMembers.fill(0);
lastMembers.at(0b0001) = 1;
for (day = 0; day < assignees.length(); day++) {
assignee = 1 << (assignees.at(day) - 'A');
members.fill(0);
for (member = 0b0001; member <= 0b1111; member++) {
for (lastMember = 0b0001; lastMember <= 0b1111; lastMember++) {
if ((member & assignee) == 0 || (member & lastMember) == 0) {
continue;
}
members.at(member) += lastMembers.at(lastMember);
members.at(member) %= MOD;
}
}
swapArray(&lastMembers, &members);
}
answer = 0;
for (int member = 0b0001; member <= 0b1111; member++) {
answer += lastMembers.at(member);
answer %= MOD;
}
return answer;
}
void solve() {
int N;
string assignees;
cin >> N;
for (int testCaseNo = 1; testCaseNo <= N; testCaseNo++) {
cin >> assignees;
cout << '#' << testCaseNo << ' ' << solveTestCase(assignees) << '\n';
}
return;
}
int main(int argc, char** argv)
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
// freopen("sample_input.txt", "r", stdin);
// freopen("sample_output.txt", "w", stdout);
solve();
return 0;
}