// 翻訳元:https://yukicoder.me/submissions/1138660 // translated by ChatGPT 5.1 #include #include using namespace std; using boost::multiprecision::cpp_int; using Int = cpp_int; // sum_{i=0}^{n-1} floor((a*i + b) / m) Int floor_sum(Int n, Int m, Int a, Int b) { Int ans = 0; if (a < 0) { Int a2 = a % m; if (a2) a2 += m; Int cnt = n * (n - 1) / 2; ans -= cnt * ((a2 - a) / m); a = a2; } if (b < 0) { Int b2 = b % m; if (b2) b2 += m; ans -= n * ((b2 - b) / m); b = b2; } if (a >= m) { Int cnt = (n - 1) * n / 2; ans += cnt * (a / m); a %= m; } if (b >= m) { ans += n * (b / m); b %= m; } Int y_max = (a * n + b) / m; Int x_max = y_max * m - b; if (y_max == 0) return ans; ans += (n - (x_max + a - 1) / a) * y_max; Int nb = -x_max % a; if (nb) nb += a; ans += floor_sum(y_max, a, m, nb); return ans; } // sum_{i=nL}^{nR-1} floor((a*i + b) / m) Int fs(Int nL, Int nR, Int m, Int a, Int b) { if (nL == nR) return Int{0}; static map, Int> mp; auto get = [&](Int N, Int M, Int A, Int B) -> Int { if (N == 0) return 0; if (mp.count({N, M, A, B})) return mp[{N, M, A, B}]; return mp[{N, M, A, B}] = floor_sum(N, M, A, B); }; return get(nR, m, a, b) - get(nL, m, a, b); } Int between(Int N, Int a1, Int b1, Int m1, Int a2, Int b2, Int m2) { auto on = [&](const Int& x) -> bool { // (a1*x + b1)/m1 > (a2*x + b2)/m2 return (a1 * x + b1) * m2 > (a2 * x + b2) * m1; }; Int nL = 0, nR = N; if (!on(nL) or !on(nR)) { if (!on(nL) and !on(nR)) return 0; // 左側: on(x) が最初に true になる点 if (!on(nL)) { nL = max(Int(0), (b2 * m1 - b1 * m2) / (a1 * m2 - a2 * m1)); while (on(nL)) nL--; while (!on(nL)) nL++; } if (nL >= nR) return 0; // 右側: on(x) が最後に true になる点 if (!on(nR)) { nR = min(Int(N), (b2 * m1 - b1 * m2) / (a1 * m2 - a2 * m1)); while (on(nR)) nR++; while (!on(nR)) nR--; } if (nL >= nR) return 0; } return fs(nL, nR, m1, a1, b1) - fs(nL, nR, m2, a2, b2); } Int calc(Int D, Int A, Int B, Int K) { K += 1; Int C = A * B / D; if (C == 0) return K * D; struct Line { Int a, b, m; }; Line L1{D, 0, A}; Line L2{D, -A, A}; Line L3{B, B * (-K + 1) - 1, C}; Line L4{B, -B * K - 1, C}; // INF = 10^50 Int INF = 1; for (int i = 0; i < 38; i++) INF *= 10; Int ng = 0, ok = INF; while (ng + 1 < ok) { Int N = (ng + ok) / 2; Int n1 = between(N + 1, L1.a, L1.b, L1.m, L4.a, L4.b, L4.m); Int n2 = between(N + 1, L1.a, L1.b, L1.m, L3.a, L3.b, L3.m); Int n3 = between(N + 1, L2.a, L2.b, L2.m, L4.a, L4.b, L4.m); Int n4 = between(N + 1, L2.a, L2.b, L2.m, L3.a, L3.b, L3.m); Int num = n1 - n2 - n3 + n4; if (num > 0) ok = N; else ng = N; } if (ok == INF) return Int(-1); return ok * D; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t = 1; if (!(cin >> t)) return 0; while (t--) { Int D, A, B, K; cin >> D >> A >> B >> K; Int ans = calc(D, A, B, K); cout << ans << '\n'; } return 0; }