https://www.acmicpc.net/problem/16998
16998번: It’s a Mod, Mod, Mod, Mod World
You are given multiple problems with three integers p, q, and n. Find
www.acmicpc.net
직접 몇 항을 써보면서 규칙을 찾아보려고 하면 알 수 있겠지만 거의 무질서 수준으로 규칙이 없다. 따라서 식을 어떻게든 잘 변형해줘야 한다. 먼저 떠올릴 수 있는 것이 다음의 자명한 공식이다.
이렇게 바꿔 주면 바닥 함수는 나머지 함수의 변화에 비해 그나마 규칙적인 것처럼 보인다는 것을 알 수 있을 것이다. 그래서 맨 처음에 주어진 공식은 다음과 같이 바꿔 쓸 수 있다.
sum 바깥에 있는 친구들은 다 상수 시간에 계산 가능하니까 sum 안쪽에 있는 것만 계산해 주면 된다. 여기서부터는 상수 시간 안에 해결되는 일반화된 공식 같은 것이 없어서 재귀함수를 돌려 줘야 한다. 몇 가지 간단한 숫자들에 대해서 생각을 해 보면, 예컨대 n = 5, p = 4, q = 7일 때 다음과 같은 그림을 그릴 수 있다.

여기서 동그라미 쳐진 격자점의 개수가 바로
이고, o 격자점과 x 격자점의 수의 합은
이다. (문제: 2번째 항이 왜 들어갈까요?) 바닥 함수의 특성에 의해 분자가 분모보다 크면 (정수 + 진분수) 꼴로 분리해서 정수 부분을 바닥 함수 밖으로 빼 줄 수 있는데 이 절차가 유클리드 호제법의 절차와 상당히 비슷하다. 따라서 시간복잡도도 유클리드 호제법의 시간복잡도를 따라간다. 절차를 q = 1 또는 n = 0 또는 p = 0이 될 때까지 반복하면 끝.
#include <bits/stdc++.h>
using i64 = long long;
i64 div_sum(i64 p, i64 q, i64 n) {
if (n == 0 or p == 0) {
return 0;
}
if (q == 1) {
return p * n * (n + 1) / 2;
}
if (p > q) {
return div_sum(p % q, q, n) + n * (n + 1) / 2 * (p / q);
}
return n * (n * p / q) + (n / q) - div_sum(q, p, n * p / q);
}
i64 mod_sum(i64 p, i64 q, i64 n) {
i64 gcd = std::gcd(p, q);
return p * n * (n + 1) / 2 - q * div_sum(p / gcd, q / gcd, n);
}
void solve() {
int t; std::cin >> t;
while (t --> 0) {
i64 p, q, n;
std::cin >> p >> q >> n;
std::cout << mod_sum(p, q, n) << '\n';
}
}
#ifndef LOCAL
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
solve();
}
#endif

'Computer Science > PS' 카테고리의 다른 글
[백준 11717] Wall Making Game [Platinum II] (0) | 2023.03.27 |
---|---|
[백준 25952] Rectangles (ICPC 2022 Seoul Internet; Diamond V) (0) | 2023.03.02 |
라빈-카프 알고리즘 구현 꿀팁 (0) | 2023.02.07 |
[백준 21117] Number of Colorful Matchings [Ruby III] (0) | 2023.02.06 |
[백준 18292] NM과 K (2) (Platinum IV) (0) | 2023.01.29 |
댓글