문제 정보
문제 링크: https://www.acmicpc.net/problem/16895
문제 요약: 돌 더미가 \(N\)개 있고, 한 턴에 돌이 있는 더미 하나를 골라 돌을 1개 이상 제거한다. 마지막 돌을 가져가는 사람이 승리한다(구사과 선공). 두 사람이 최적으로 플레이할 때, 구사과가 첫 턴에 선택할 수 있는 “승리하는 첫 수”의 개수를 출력한다.
제한 조건:
- 시간 제한: 1초
- 메모리 제한: 512MB
- \(1 \le N \le 1000\)
- \(1 \le P_i \le 1000\)
입출력 예제
입력:
| |
출력:
| |
접근 방식
핵심 관찰
님 게임(정상 규칙, impartial game)의 표준 정리:
- 모든 더미 크기의 XOR 값을 \(X\)라고 하면, \(X=0\)인 상태는 패배 상태(선 플레이어 필패)이다.
- \(X \ne 0\)이면, 어떤 더미 \(p_i\)를 \(p_i' = p_i \oplus X\)로 바꿔서(즉 \(p_i'\)만 남도록 돌을 제거) XOR를 0으로 만드는 수가 존재하며, 그런 수는 모두 승리 수다.
따라서 “첫 수로 이길 수 있는 방법 수”는 다음을 세면 된다.
- \(X = p_1 \oplus p_2 \oplus \cdots \oplus p_N\)
- \(X=0\)이면 답은 0
- \(X \ne 0\)이면, 각 더미에 대해 \(t = p_i \oplus X\)를 계산해서 \(t < p_i\)인 경우의 개수를 센다.
- 이때 \(p_i\)에서 \(p_i - t\)개를 제거하면 새로운 XOR가 0이 된다.
알고리즘 흐름(mermaid)
flowchart TD
A["입력: N, P 배열"] --> B["전체 XOR 계산"]
B --> C{"XOR가 0인가"}
C -->|"예"| D["정답 0 출력"]
C -->|"아니오"| E["각 더미에 대해 t = pi XOR X 계산"]
E --> F{"t가 pi보다 작은가"}
F -->|"예"| G["정답 카운트 증가"]
F -->|"아니오"| H["다음 더미"]
G --> H
H --> I["모든 더미 처리 후 정답 출력"]
정당성(간단 증명)
- \(X=0\)인 상태에서 어떤 한 더미를 줄이면 전체 XOR는 0이 아니게 된다. 즉 다음 플레이어에게 \(X \ne 0\) 상태를 넘겨주게 되고, 최적 플레이에서는 현재 플레이어가 결국 패한다(표준 님 정리).
- \(X \ne 0\)인 상태에서는 \(X\)의 최상위 1비트가 존재하고, 그 비트가 1인 더미를 하나 골라 \(p_i' = p_i \oplus X\)로 줄일 수 있다. 이때 새로운 XOR는 \[ X \oplus p_i \oplus p_i' = X \oplus p_i \oplus (p_i \oplus X) = 0 \] 이므로 상대를 패배 상태로 보낼 수 있다.
- 가능한 모든 첫 수는 “어떤 \(i\)에 대해 \(t=p_i \oplus X < p_i\)”인 경우와 1:1로 대응하므로, 그 개수가 정답이다.
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O(N)\) | XOR 1회 + 더미 1회 순회 |
| 공간 복잡도 | \(O(1)\) | 입력 저장을 제외하면 상수 |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| XOR=0 | 선공이 이길 수 있는 첫 수가 없음 | 즉시 0 출력 |
| N=1 | 한 더미만 있는 경우 | 항상 XOR≠0이므로 답은 1 |
| t=pi | 제거량이 0이 되는 경우(불가능한 수) | \(t |
구현 코드 (C++)
| |
![Featured image of post [Algorithm] C++ 백준 16895번: 님 게임 3](/post/algorithm/2025-12-19-boj-16895-nim-game-3-cpp-solution/wordcloud_hu_30bd649aed180c76.png)
![[Algorithm] C++ 백준 15249번: Building Bridges](/post/algorithm/2025-12-19-boj-15249-building-bridges-cpp-solution/wordcloud_hu_74e7f50c7caada4c.png)
![[Algorithm] C++ 백준 16745번: What Goes Up Must Come Down](/post/algorithm/2025-12-19-boj-16745-what-goes-up-must-come-down-cpp-solution/wordcloud_hu_8b312f25f2104ffa.png)
![[Algorithm] C++ 백준 16895번: 님 게임 3](/post/algorithm/2025-12-19-boj-16895-nim-game-3-cpp-solution/wordcloud_hu_f071b137bed4b6a4.png)
![[Algorithm] C++ 백준 17441번: 파리채 만들기](/post/algorithm/2025-12-19-boj-17441-fly-swatter-making-green-theorem-cpp-solution/wordcloud_hu_f4a8a47eafcd5a3b.png)
![[Algorithm] C++ 백준 1777번: 순열복원](/post/algorithm/2025-12-19-boj-1777-permutation-recovery-cpp-solution/wordcloud_hu_e783e8b2198c2957.png)
![[Algorithm] C++ 백준 17965번: Absolute Game](/post/algorithm/2025-12-19-boj-17965-absolute-game-cpp-solution/wordcloud_hu_f6800a55fcd520be.png)
![[Algorithm] C++ 백준 32115번: 돌 놓기 게임](/post/algorithm/2025-12-19-boj-32115-stone-placing-game-cpp-solution/wordcloud_hu_b5570483586eb270.png)
![[Algorithm] C++ 백준 25201번: 보드 뒤집기 게임](/post/algorithm/2025-12-19-boj-25201-board-flipping-game-cpp-solution/wordcloud_hu_22b1d8c414e9b6d9.png)
![[Algorithm] C++ 백준 11868번: 님 게임 2](/post/algorithm/2025-12-08-boj-11868-nim-game-2-game-theory-cpp-solution/wordcloud_hu_cb52f0251e1b8fbb.png)
![[Algorithm] C++ 백준 2988번: 아보가드로](/post/algorithm/2025-12-19-boj-2988-avogadro-cpp-solution/wordcloud_hu_504f3f1bc728ef52.png)