結果
問題 |
No.849 yuki国の分割統治
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:15:40 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 54 ms / 2,000 ms |
コード長 | 7,081 bytes |
コンパイル時間 | 1,260 ms |
コンパイル使用メモリ | 107,980 KB |
実行使用メモリ | 9,984 KB |
最終ジャッジ日時 | 2025-05-14 13:17:00 |
合計ジャッジ時間 | 3,742 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 26 |
ソースコード
#include <iostream> #include <vector> #include <set> #include <utility> // std::pair #include <numeric> // std::gcd #include <cmath> // std::abs #include <string> // For printing __int128_t (optional, mainly for debugging) #include <algorithm> // For std::reverse in __int128_t printing helper // Use __int128_t type for calculations that might exceed 64 bits using int128 = __int128_t; // Function to compute GCD for long long integers. // std::gcd requires non-negative arguments in some older standards/versions. // C++17 std::gcd handles signed integers correctly, returning non-negative result. // Using std::abs for safety and clarity. long long compute_gcd(long long x, long long y) { return std::gcd(std::abs(x), std::abs(y)); } // Function for modular arithmetic that correctly handles negative results of % operator. // Assumes mod > 0. long long safe_modulo(long long val, long long mod) { // Check for modulo by zero, although logic should prevent this. if (mod == 0) { // Based on problem logic D_abs > 0 for D!=0 case. // This path indicates an issue. Return 0 or handle error. return 0; } // The C++ % operator can return negative results for negative input 'val'. long long res = val % mod; // Adjust negative result to be in [0, mod-1] if (res < 0) { res += mod; } return res; } // Similar function for __int128_t type. Assumes mod > 0. int128 safe_modulo128(int128 val, int128 mod) { // Check for modulo by zero, although logic should prevent this. if (mod == 0) { // Based on problem logic M > 0 for D=0 case. // This path indicates an issue. Return 0 or handle error. return 0; } // The C++ % operator can return negative results for negative input 'val'. int128 res = val % mod; // Adjust negative result to be in [0, mod-1] if (res < 0) { res += mod; } return res; } // Helper function to print __int128_t. This is useful for debugging purposes. // Standard iostream doesn't support __int128_t directly. std::ostream& operator<<(std::ostream& os, int128 val) { if (val == 0) return os << "0"; std::string s = ""; bool neg = false; if (val < 0) { neg = true; val = -val; // Make positive for digit extraction } while (val > 0) { s += (char)('0' + (val % 10)); val /= 10; } if (neg) os << "-"; // Print sign if negative std::reverse(s.begin(), s.end()); // Digits are extracted in reverse order return os << s; } int main() { // Faster I/O std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); long long a, b, c, d; std::cin >> a >> b >> c >> d; int N; std::cin >> N; std::vector<std::pair<long long, long long>> P(N); for (int i = 0; i < N; ++i) { std::cin >> P[i].first >> P[i].second; } // Compute determinant D = ad - bc. Use __int128_t to avoid overflow during multiplication. int128 D_128 = (int128)a * d - (int128)b * c; // The final value of D fits within long long based on analysis. long long D = (long long)D_128; if (D != 0) { // Case 1: Vectors v1=(a,b) and v2=(c,d) are linearly independent. // The equivalence classes are determined by coordinates modulo D. long long D_abs = std::abs(D); // Since D != 0, D_abs must be > 0. No need to check for D_abs == 0. // Use a set to store unique pairs representing groups. std::set<std::pair<long long, long long>> distinct_groups; for (int i = 0; i < N; ++i) { long long x_i = P[i].first; long long y_i = P[i].second; // Calculate the transformed coordinates (X_i, Y_i). Need long long for intermediate products. long long X_i = (long long)d * x_i - (long long)c * y_i; long long Y_i = (long long)a * y_i - (long long)b * x_i; // Compute the canonical representative pair modulo D_abs. long long R1 = safe_modulo(X_i, D_abs); long long R2 = safe_modulo(Y_i, D_abs); // Insert the pair into the set. The set automatically handles uniqueness. distinct_groups.insert({R1, R2}); } // The size of the set is the number of distinct groups. std::cout << distinct_groups.size() << std::endl; } else { // D == 0 // Case 2: Vectors v1=(a,b) and v2=(c,d) are linearly dependent (parallel). // The lattice L is 1-dimensional, generated by a vector v = G*u. // Calculate gcd for v1=(a,b). It's guaranteed > 0 because (a,b)!=(0,0). long long g = compute_gcd(a, b); // Calculate the primitive vector u parallel to v1. long long u_x = 0, u_y = 0; if (g != 0) { // This check is technically redundant due to constraints. u_x = a / g; u_y = b / g; } // Calculate gcd for v2=(c,d). Guaranteed > 0 because (c,d)!=(0,0). long long h = compute_gcd(c, d); // Canonicalize the primitive vector u. // Ensure uniqueness: first non-zero component positive, or if first is zero, second positive. if (u_x < 0 || (u_x == 0 && u_y < 0)) { u_x = -u_x; u_y = -u_y; } // Calculate G = gcd(g, h). Guaranteed > 0 since g, h > 0. long long G = compute_gcd(g, h); // Calculate the modulus M = G * ||u||^2 using __int128_t to avoid overflow. int128 G_128 = G; int128 u_x_128 = u_x; int128 u_y_128 = u_y; // Norm squared ||u||^2 = u_x^2 + u_y^2. It must be > 0 since u is primitive for a non-zero vector. int128 u_norm_sq = u_x_128 * u_x_128 + u_y_128 * u_y_128; int128 M = G_128 * u_norm_sq; // M > 0 based on logic. // Use a set to store unique pairs representing groups. Pair uses long long and __int128_t. std::set<std::pair<long long, int128>> distinct_groups; for (int i = 0; i < N; ++i) { long long x_i = P[i].first; long long y_i = P[i].second; // Calculate invariant K'_i (related to projection onto line perpendicular to u). // Fits within long long. long long K_prime_i = (long long)x_i * u_y - (long long)y_i * u_x; // Calculate invariant S_i (related to projection onto line parallel to u). // Fits within long long. long long S_i = (long long)x_i * u_x + (long long)y_i * u_y; // Compute the canonical representative S_i mod M using __int128_t. int128 S_i_128 = S_i; int128 R_S = safe_modulo128(S_i_128, M); // Note: If M=1, R_S will correctly be 0. // Insert the pair (K'_i, R_S) into the set. distinct_groups.insert({K_prime_i, R_S}); } // The size of the set is the number of distinct groups. std::cout << distinct_groups.size() << std::endl; } return 0; }