結果

問題 No.2359 A in S ?
ユーザー qwewe
提出日時 2025-05-14 13:14:26
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 1,721 ms / 2,000 ms
コード長 9,806 bytes
コンパイル時間 1,122 ms
コンパイル使用メモリ 104,420 KB
実行使用メモリ 133,628 KB
最終ジャッジ日時 2025-05-14 13:15:49
合計ジャッジ時間 8,203 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 18
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <cmath>
#include <numeric> 
#include <algorithm> // For std::max, std::min

// Custom function for ceiling division: ceil(a / b)
// Assumes b > 0
long long ceil_div(long long a, long long b) {
    // Standard C++ integer division truncates towards zero.
    if (a >= 0) {
        // For non-negative a, use standard formula (a + b - 1) / b
        return (a + b - 1) / b;
    } else {
        // For negative a, standard division a / b effectively computes ceiling.
        // E.g., -3 / 2 = -1, ceil(-1.5) = -1. -4 / 2 = -2, ceil(-2) = -2.
        return a / b; 
    }
}

// Custom function for floor division: floor(a / b)
// Assumes b > 0
long long floor_div(long long a, long long b) {
    // Standard C++ integer division truncates towards zero.
    long long res = a / b;
    // If a is negative and not perfectly divisible by b, standard division gives ceiling.
    // Floor is one less in this case.
    if (a < 0 && a % b != 0) {
        res--; 
    }
    return res;
}


int main() {
    // Use fast IO
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int N, M;
    std::cin >> N >> M;

    std::vector<int> L(N), R(N), X(N), Y(N);
    int max_coord = 0; // Keep track of the maximum coordinate value seen
    for (int i = 0; i < N; ++i) {
        std::cin >> L[i] >> R[i] >> X[i] >> Y[i];
        // Basic validation based on problem constraints
        // L_i >= 1, R_i >= L_i, X_i >= 1, 0 <= Y_i < X_i
        // We assume inputs adhere to constraints, but add minor guards if needed.
        if (L[i] < 1) L[i] = 1; // Enforce L_i >= 1
        if (R[i] < L[i]) R[i] = L[i]; // Enforce R_i >= L_i
        if (X[i] < 1) X[i] = 1; // Enforce X_i >= 1
        if (Y[i] < 0 || Y[i] >= X[i]) Y[i] = Y[i] % X[i]; // Ensure Y[i] is in [0, X[i]-1]
        if (Y[i] < 0) Y[i] += X[i]; 

        max_coord = std::max(max_coord, R[i]);
    }

    std::vector<int> A(M);
    for (int j = 0; j < M; ++j) {
        std::cin >> A[j];
        // A_j >= 1
        if (A[j] < 1) A[j] = 1; // Enforce A_j >= 1
        max_coord = std::max(max_coord, A[j]);
    }

    int V = max_coord; // The maximum coordinate value determines the range needed
    if (V == 0) V = 1; // Handle edge case where all coordinates are 0 (unlikely given constraints)
    
    // Set the threshold B for splitting into "small X" and "large X" cases
    // B = sqrt(V) is a common choice for balancing complexity
    int B = static_cast<int>(sqrt(V));
    if (B <= 0) B = 1; // Ensure B is at least 1

    // Array to store counts contributed by conditions with large X_i (> B)
    std::vector<int> count_large(V + 1, 0);

    // Structure to group indices i based on (X_i, Y_i) pair for small X_i (<= B)
    // groups[x][y] stores a list of indices i such that X_i = x and Y_i = y
    std::vector<std::vector<std::vector<int>>> groups(B + 1);
     for(int x_val = 1; x_val <= B; ++x_val) {
         groups[x_val].resize(x_val); // Allocate inner vectors for Y values [0, x_val-1]
     }

    // Process each condition (L_i, R_i, X_i, Y_i)
    for (int i = 0; i < N; ++i) {
        if (X[i] == 0) continue; // Invalid X[i], skip (though constraints say X_i >= 1)
        
        if (X[i] > B) { // Case 1: Large X_i
            // Directly compute the values k satisfying the condition and update count_large
            long long k_min;
            int Li = L[i];
            int Ri = R[i];
            int Xi = X[i];
            int Yi = Y[i];

            // Calculate the smallest k >= Li such that k = Yi (mod Xi)
            long long rem = (long long)Li % Xi; // Since Li >= 1, Xi >= 1, rem is in [0, Xi-1]
            
            if (rem <= Yi) {
                k_min = (long long)Li + (Yi - rem);
            } else { // rem > Yi
                k_min = (long long)Li + (Xi - rem) + Yi;
            }
            
            // If the smallest valid k is already outside the range [Li, Ri], skip
            if (k_min > Ri) continue; 

            // Iterate through the arithmetic progression k = k_min, k_min + Xi, ...
            for (long long k = k_min; k <= Ri; k += Xi) {
                 // Increment count only if k is within the valid coordinate range [1, V]
                 if (k >= 1 && k <= V) { 
                    count_large[k]++;
                 } else if (k > V) { // Optimization: stop if k exceeds V
                     break;
                 }
            }

        } else { // Case 2: Small X_i (X_i <= B)
             // Group the index i based on its (X_i, Y_i) pair
             if (Y[i] >= 0 && Y[i] < X[i]) { // Ensure Y[i] is valid index
                 groups[X[i]][Y[i]].push_back(i);
             }
        }
    }

    // Precompute counts for small X cases using difference arrays / sweep line approach
    // all_count_q[x][y][q] will store the number of conditions i with (X_i, Y_i) = (x, y)
    // such that the value k = y + q*x satisfies L_i <= k <= R_i.
    std::vector<std::vector<std::vector<int>>> all_count_q(B + 1);
     for(int x_val = 1; x_val <= B; ++x_val) {
         all_count_q[x_val].resize(x_val); // Allocate inner vectors
     }

    // Process each pair (X, Y) with X <= B
    for (int X_val = 1; X_val <= B; ++X_val) {
        for (int Y_val = 0; Y_val < X_val; ++Y_val) {
            // Check if there are any conditions for this (X, Y) pair
            if (!groups[X_val][Y_val].empty()) { 
                
                // Calculate the maximum possible index q such that Y_val + q * X_val <= V
                long long Q_max_ll = floor_div((long long)V - Y_val, X_val);
                // Check basic validity: if max q is negative, or results in k < 1
                if (Q_max_ll < 0 || (Y_val == 0 && Q_max_ll < 1) ) continue; 
                int Q_max = static_cast<int>(Q_max_ll);

                // Difference array for sweep line on q indices. Size Q_max + 2 for index Q_max + 1.
                std::vector<int> diff(Q_max + 2, 0); 

                // Populate difference array based on q intervals for each condition i in the group
                for (int i : groups[X_val][Y_val]) {
                    long long q_start, q_end;

                    // Calculate the interval [q_start, q_end] for index q
                    if (Y_val == 0) { // Special case Y=0: k = q*X. Need k >= L[i] and k >= 1.
                        q_start = ceil_div((long long)L[i], X_val);
                        q_start = std::max(1LL, q_start); // Ensure q >= 1 because k must be >= 1
                        q_end = floor_div((long long)R[i], X_val);
                    } else { // Case Y > 0: k = Y + q*X. Need k >= L[i]. k >= 1 is true for q >= 0.
                        q_start = ceil_div((long long)L[i] - Y_val, X_val);
                        q_start = std::max(0LL, q_start); // Ensure q >= 0
                        q_end = floor_div((long long)R[i] - Y_val, X_val);
                    }

                    // If the calculated interval is valid
                    if (q_start <= q_end) {
                         // Clamp the interval [q_start, q_end] to the valid range [0, Q_max]
                         q_start = std::max(q_start, 0LL); 
                         q_end = std::min(q_end, (long long)Q_max); 

                         // Apply updates to difference array if interval is still valid after clamping
                         if (q_start <= q_end) { 
                             diff[q_start]++; // Increment count at start of interval
                             if (q_end + 1 <= Q_max + 1) { // Check bounds for difference array access
                                 diff[q_end + 1]--; // Decrement count after end of interval
                             }
                         }
                    }
                }

                // Compute prefix sums of the difference array to get the actual counts for each q
                all_count_q[X_val][Y_val].resize(Q_max + 1);
                int current_count = 0;
                for (int q = 0; q <= Q_max; ++q) { 
                    current_count += diff[q];
                    all_count_q[X_val][Y_val][q] = current_count;
                }
            }
        }
    }

    // Answer each query A_j
    for (int j = 0; j < M; ++j) {
        int Aj = A[j];
        // Check if Aj is within the valid coordinate range [1, V]
        if (Aj <= 0 || Aj > V) { 
             std::cout << 0 << "\n"; // Aj is outside the range, count must be 0
             continue;
        }
        
        // Initialize total count with contribution from large X conditions
        long long total_count = count_large[Aj];

        // Add contributions from small X conditions
        for (int X_val = 1; X_val <= B; ++X_val) {
             // Determine the remainder Y_val corresponding to Aj for this X_val
             int Y_val = Aj % X_val; // Y_val will be in [0, X_val-1] for positive Aj, X_val

             // Check if this group (X_val, Y_val) has precomputed counts
             if (Y_val < all_count_q[X_val].size() && !all_count_q[X_val][Y_val].empty()) { 
                 // Calculate the index q corresponding to Aj: Aj = Y_val + qj * X_val
                 long long qj = (long long)(Aj - Y_val) / X_val; // Integer division is exact since Aj % X_val = Y_val
                 
                 int Q_max_for_pair = all_count_q[X_val][Y_val].size() - 1;

                 // Check if qj is within the valid range [0, Q_max_for_pair] for this group
                 if (qj >= 0 && qj <= Q_max_for_pair) {
                     // Add the precomputed count for this qj
                     total_count += all_count_q[X_val][Y_val][qj];
                 }
             }
        }
        // Output the final count for Aj
        std::cout << total_count << "\n";
    }

    return 0;
}
0