ax²+b mod N 점화식으로 다음 사람을 선택하는 게임에서 술을 마시지 않는 사람의 수를 구하는 문제입니다.
처음에는 HashMap으로 방문 횟수를 관리했으나 메모리 초과가 났고,
플로이드 순환 찾기 알고리즘(토끼와 거북이)으로 다시 풀었습니다.
HashMap은 엔트리당 약 80 bytes의 객체 오버헤드가 있어서
최대 2×10^6 엔트리 × 80 bytes = 160MB → 메모리 제한 128MB 초과
수열 구조:
0 → x₁ → x₂ → ... → 입구 → ... → 입구 (순환)
↑ 고리 밖 (L명) ↑ 고리 안 (C명)
1단계: 순환 고리 안으로 진입
long tortoise = next(0, a, b, N);
long hare = next(next(0, a, b, N), a, b, N);
while (tortoise != hare) {
tortoise = next(tortoise, a, b, N);
hare = next(next(hare, a, b, N), a, b, N);
}
2단계: 순환 입구 찾기
tortoise = 0;
while (tortoise != hare) {
tortoise = next(tortoise, a, b, N);
hare = next(hare, a, b, N);
}
3단계: 고리 길이 측정
long cycleLength = 1;
long current = next(tortoise, a, b, N);
while (current != tortoise) {
current = next(current, a, b, N);
cycleLength++;
}
L: 시작점 → 순환 입구까지 거리
C: 순환 고리 길이
d: 순환 입구 → 첫 만남 지점까지 거리
L + d = nC → L = nC - d
거북이를 0으로 보내면
거북이: L만큼 이동 → 입구 도착
토끼: nC-d만큼 이동 → 입구 도착
→ 둘이 정확히 입구에서 만남
static long next(long x, long a, long b, long N) {
long x2 = (x * x) % N;
long ax2 = (a * x2) % N;
return (ax2 + b) % N;
}
중간마다 % N 을 해줘야 오버플로우 방지
O(L + C)O(1)package B6523;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
while (true) {
String line = br.readLine();
StringTokenizer st = new StringTokenizer(line);
long N = Long.parseLong(st.nextToken());
if (N == 0) break;
long a = Long.parseLong(st.nextToken());
long b = Long.parseLong(st.nextToken());
long tortoise = next(0, a, b, N);
long hare = next(next(0, a, b, N), a, b, N);
while (tortoise != hare) {
tortoise = next(tortoise, a, b, N);
hare = next(next(hare, a, b, N), a, b, N);
}
tortoise = 0;
while (tortoise != hare) {
tortoise = next(tortoise, a, b, N);
hare = next(hare, a, b, N);
}
long cycleLength = 1;
long current = next(tortoise, a, b, N);
while (current != tortoise) {
current = next(current, a, b, N);
cycleLength++;
}
sb.append(N - cycleLength).append("\n");
}
System.out.print(sb);
}
static long next(long x, long a, long b, long N) {
long x2 = (x * x) % N;
long ax2 = (a * x2) % N;
return (ax2 + b) % N;
}
}