結果

問題 No.849 yuki国の分割統治
ユーザー qwewe
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

diff #

#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;
}
0