結果
問題 |
No.752 mod数列
|
ユーザー |
![]() |
提出日時 | 2025-05-14 12:58:59 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 7,326 bytes |
コンパイル時間 | 515 ms |
コンパイル使用メモリ | 68,896 KB |
実行使用メモリ | 16,072 KB |
最終ジャッジ日時 | 2025-05-14 13:00:14 |
合計ジャッジ時間 | 5,510 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | -- * 3 |
other | AC * 16 TLE * 1 -- * 14 |
ソースコード
#include <iostream> // Using unsigned __int128 for intermediate calculations to prevent overflow. // The problem involves sums that can exceed the capacity of standard 64-bit integers (long long), // especially during intermediate product calculations. `unsigned __int128` is a non-standard // extension available in GCC and Clang that provides 128-bit integer arithmetic. // The final results are expected to fit within a standard `long long`. /** * @brief Computes the sum of P mod n for n in the range [L, R]. * * The sequence is defined as a_n = P mod n. We need to compute Sum_{n=L}^{R} a_n. * The calculation uses the identity P mod n = P - n * floor(P/n). * The sum is split into two parts: n <= P and n > P. * For n > P, P mod n = P. * For n <= P, we compute Sum (P - n * floor(P/n)) = (Count * P) - Sum (n * floor(P/n)). * The sum Sum (n * floor(P/n)) is computed efficiently using block summation based on the * observation that floor(P/n) takes on O(sqrt(P)) distinct values. * * @param P The integer P used in the modulo operation. * @param L The start of the range (inclusive). * @param R The end of the range (inclusive). * @return The sum Sum_{n=L}^{R} (P mod n) as a long long. */ long long compute_sum_range(long long P, long long L, long long R) { // Handle invalid range where L > R. The sum is 0. if (L > R) return 0LL; // Use 128 bit integer type for accumulating the total sum to avoid potential overflow issues. unsigned __int128 total_sum_mod = 0; // --- Part 1: Handle the portion of the range where n > P --- // If the entire range [L, R] is above P, then for all n in [L, R], P mod n = P. if (L > P) { // The sum is simply (R - L + 1) * P. // Use 128-bit types for calculation to avoid overflow if R-L+1 is large. unsigned __int128 count_gt_P = 0; // Ensure R >= L before calculating count to avoid underflow issues with unsigned types if (R >= L) count_gt_P = (unsigned __int128)(R - L + 1); unsigned __int128 P_u128 = P; total_sum_mod = count_gt_P * P_u128; return (long long)total_sum_mod; // Cast the final result back to long long } // If the range [L, R] partially overlaps with n > P (i.e., L <= P < R) long long current_R = R; // Use current_R to track the upper bound for calculations involving n <= P if (R > P) { // Calculate the sum for n in the range [P+1, R]. For these n, P mod n = P. // The sum is (R - (P+1) + 1) * P = (R - P) * P. unsigned __int128 count_gt_P = (unsigned __int128)(R - P); unsigned __int128 P_u128 = P; total_sum_mod += count_gt_P * P_u128; current_R = P; // Adjust the upper bound to P for the subsequent calculation part } // --- Part 2: Handle the portion of the range where n <= P --- // Now we need to compute the sum for n in the range [L, current_R], where current_R <= P. long long current_L = L; // Start from the original L // Ensure current_L is at least 1, as the problem constraints state L >= 1. // This also prevents potential issues with division by zero if P/n is calculated for n=0. if (current_L < 1) current_L = 1; // If after adjustments (like L starting > P, or R being adjusted down to P), // current_L becomes greater than current_R, it means this part of the range is empty. // We just return the sum accumulated so far (from the n > P part, if any). if (current_L > current_R) { return (long long)total_sum_mod; } // Use the formula: Sum_{n=current_L}^{current_R} (P mod n) = Sum_{n=current_L}^{current_R} (P - n * floor(P/n)) // Which expands to: (current_R - current_L + 1) * P - Sum_{n=current_L}^{current_R} n * floor(P/n) // We compute Sum_{n=current_L}^{current_R} n * floor(P/n) using block summation. unsigned __int128 sum_n_floor_Pn = 0; // Accumulator for the sum n * floor(P/n) part long long n = current_L; // Start iterating from current_L while (n <= current_R) { // Calculate k = floor(P/n). Since n is constrained current_L <= n <= current_R <= P, // and P >= 1, n >= 1, k will always be >= 1. Division by zero is not possible. long long k = P / n; // Find the largest n' in the range [n, current_R] such that floor(P/n') = k. // This is given by floor(P/k). long long n_max_for_k = P / k; // Safe division since k >= 1 // The current block ends at min(current_R, n_max_for_k). long long n_end = current_R < n_max_for_k ? current_R : n_max_for_k; // Compute the sum of the arithmetic series: Sum_{i=n}^{n_end} i // Formula: (count * (first + last)) / 2 // Use 128-bit intermediate calculations for safety. unsigned __int128 first = n; unsigned __int128 last = n_end; unsigned __int128 count = 0; if (last >= first) count = last - first + 1; // Calculate count safely unsigned __int128 sum_arith_series = 0; if (count > 0) { // Use property that count * (first + last) is always even. // Perform division first where possible to mitigate overflow risk, although with 128-bit it's less critical. if (count % 2 == 0) { sum_arith_series = (count / 2) * (first + last); } else { // If count is odd, (first + last) must be even. sum_arith_series = count * ((first + last) / 2); } } // Compute the contribution of this block: k * sum_arith_series unsigned __int128 term = (unsigned __int128)k * sum_arith_series; sum_n_floor_Pn += term; // Add to the accumulator sum_n_floor_Pn // Move to the start of the next block. // Check for potential infinite loop if n_end doesn't advance n. // This typically shouldn't happen with correct logic but serves as a safeguard. if (n_end < n) { break; // Should not occur, indicates a logic flaw if it does. } n = n_end + 1; } // Add the sum contribution from the range [current_L, current_R] to the total sum. unsigned __int128 P_u128 = P; unsigned __int128 count_le_P = 0; if (current_R >= current_L) count_le_P = (unsigned __int128)(current_R - current_L + 1); // total_sum_mod += (Sum P) - (Sum n*floor(P/n)) total_sum_mod += count_le_P * P_u128 - sum_n_floor_Pn; // Return the final total sum, cast back to long long. return (long long)total_sum_mod; } int main() { // Use faster I/O operations std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); long long P; // The parameter P for the modulo sequence int Q; // The number of queries std::cin >> P >> Q; // Process each query for (int i = 0; i < Q; ++i) { long long L, R; // Range for the current query std::cin >> L >> R; // Compute the sum for the query range [L, R] long long res = compute_sum_range(P, L, R); // Output the result for the current query std::cout << res << "\n"; // Use "\n" instead of std::endl for potentially faster output flushing } return 0; // Indicate successful execution }