D(N)을 다음과 같이 쓰자.
D(N)=x=1∑Nτ(x).
τ(x)는 ab=x를 만족하는 양의 정수 순서쌍 (a,b)의 개수이다. 따라서
D(N)=#{(a,b)∈Z>02:ab≤N}=a=1∑N⌊aN⌋.
즉, 문제는 쌍곡선 xy=N 아래의 양의 정수 격자점 수를 세는 문제이다.
서브태스크 1
N≤106이면 위 합을 그대로 계산할 수 있다. 시간 복잡도는 O(N)이다.
서브태스크 2
쌍곡선은 x=y에 대해 대칭이다. X=⌊N⌋라 하면
D(N)=2x=1∑X⌊xN⌋−X2.
따라서 O(N)에 계산할 수 있고, N≤1012에서는 충분하다.
전체 서브태스크
N≤1018에서는 O(N)도 충분하지 않다. 정해는 Richard Sladkey의 successive approximation 방법을 사용하여 격자점 수를 O(N1/3) 시간, O(logN) 추가 공간에 계산한다.
먼저
Xmax=⌊N⌋,Ymin=⌊XmaxN⌋
를 두고, 구현에서는
Xmin=min(Xmax, 2⌈32N⌉)
로 둔다. x<Xmin인 열은 직접 합산한다. 이 부분은 O(N1/3)이다.
나머지 부분에서는 쌍곡선에 가까운 정수 직선들을 이용해 영역을 나눈다. 두 경계 직선을
L1:a1x+b1y=c1,L2:a2x+b2y=c2
라 하자. 기울기들이 Farey neighbor가 되도록 잡아
a1b2−a2b1=1
을 만족시킨다.
새 좌표를
u=a1x+b1y−c1,v=a2x+b2y−c2
로 정의하면 행렬식이 1이므로 정수 격자점이 일대일 대응한다. 역변환은
x=b2(u+c1)−b1(v+c2),
y=a1(v+c2)−a2(u+c1)
이다.
이 좌표에서 쌍곡선 위의 v를 u의 함수로 풀면
V(u)=2a1b1(a1b2+b1a2)(u+c1)−(u+c1)2−4a1b1N−c2.
마찬가지로
U(v)=2a2b2(a1b2+b1a2)(v+c2)−(v+c2)2−4a2b2N−c1.
영역의 너비나 높이가 작은 경우에는 ⌊V(u)⌋ 또는 ⌊U(v)⌋를 직접 더한다.
그렇지 않으면 mediant
a3=a1+a2,b3=b1+b2
를 사용한다. 새 좌표에서 기울기가 −1인 접점의 u좌표는
utan=(a1b2+b1a2+2a1b1)a3b3N−c1
이다. u4=⌊utan⌋, u5=u4+1로 두고
v4=⌊V(u4)⌋,v5=⌊V(u5)⌋,
v6=u4+v4,u7=u5+v5
를 계산한다.
Δ(k)=k(k+1)/2라 하면 가운데 다각형의 격자점 수는 구현에서
Δ(v6−1)−Δ(v6−u5)+Δ(u7−u5)
로 계산할 수 있다. 남은 두 영역은 각각 (a1/b1,a3/b3)와 (a3/b3,a2/b2)를 경계로 하므로 같은 함수를 재귀 호출한다.
최상위에서는 기울기 −1,−2,−3,…에 해당하는 영역을 차례로 처리한다. 기울기 −a 부근의 접점은 x≈N/a이므로, x<Xmin이 되면 중단하고 남은 짧은 부분을 직접 계산한다. 각 단계의 삼각형 부분은 삼각수로 즉시 더할 수 있다.
이 방법이 방문하는 전체 영역 수는 O(N1/3)이고 재귀 깊이는 O(logN)이다. 따라서 전체 시간 복잡도는 O(N1/3), 추가 공간 복잡도는 O(logN)이다.
N=1018이면 D(N) 자체는 signed 64-bit 범위를 넘을 수 있다. 정답을 정확히 세는 중간 합에는 __int128을 사용하고, 마지막에만 998244353으로 나눈다. 쌍곡선과 제곱근 판정에 필요한 곱셈도 __int128으로 계산한다.
Solution written by GPT5.6