公式

D - 通路の扉と体力 / Corridor Doors and Hit Points 解説 by admin

Claude 4.6 Opus (Thinking)

Overview

This problem requires building a function that computes the sum of “weights” (number of locks) of doors over an interval at a fixed time, then using binary search to find the farthest reachable room in both the left and right directions.

Analysis

Structure of Door Weights

When we fix time \(T\), security pattern \(i\) places a lock on door \(x\) under the condition: $\(x \equiv C_i \pmod{A_i} \quad \text{where } C_i = (R_i + V_i \cdot T) \bmod A_i\)$

In other words, pattern \(i\) places locks on doors at positions forming an arithmetic sequence: \(C_i, C_i + A_i, C_i + 2A_i, \ldots\)

Sum of Weights in an Interval

The total weight of doors in the interval \([lo, hi]\) is the sum over each pattern \(i\) of “how many \(x\) in \([lo, hi]\) satisfy \(x \equiv C_i \pmod{A_i}\)”. This can be computed in \(O(N)\) using the following formula:

\[\text{count}_i = \left\lfloor \frac{hi - C_i}{A_i} \right\rfloor - \left\lfloor \frac{lo - 1 - C_i}{A_i} \right\rfloor\]

Monotonicity and Binary Search

To move \(k\) rooms to the right from room \(S\), one must pass through doors \(S+1, S+2, \ldots, S+k\). As \(k\) increases, the number of doors traversed increases, so the total weight is monotonically non-decreasing. Therefore, the maximum \(k\) satisfying “total weight \(\leq P\)” can be found using binary search. The same applies to the left direction.

Why the Complexity is Feasible

The key constraint is \(N \times Q \leq 3 \times 10^5\). For each query, we perform binary search twice, and each step requires \(O(N)\) computation. Since \(\log L \leq 30\) or so, the overall complexity is \(O(N \times Q \times \log L) \approx 9 \times 10^6\), which is well within the time limit.

Algorithm

  1. For each query \((T_j, S_j, P_j)\):

    • Compute \(C_i = (R_i + V_i \cdot T_j) \bmod A_i\) for each pattern \(i\).
    • Binary search to the right: Find the maximum \(k\) (\(0 \leq k \leq L-1-S\)) satisfying \(\text{total\_weight}(S+1, S+k) \leq P\).
    • Binary search to the left: Find the maximum \(k\) (\(0 \leq k \leq S\)) satisfying \(\text{total\_weight}(S-k+1, S) \leq P\).
    • The answer is \(\text{left\_rooms} + \text{right\_rooms} + 1\) (including the starting room itself).
  2. total_weight(lo, hi) sums the contribution of each pattern using the formula described above.

Concrete Example

Consider a pattern with \(A=3, C=1\), and doors in the interval \([1, 7]\). The doors with locks are \(1, 4, 7\) — a total of 3. $\(\left\lfloor \frac{7-1}{3} \right\rfloor - \left\lfloor \frac{0-1}{3} \right\rfloor = 2 - (-1) = 3\)$

Complexity

  • Time complexity: \(O(N \cdot Q \cdot \log L)\) (Since the constraint gives \(N \cdot Q \leq 3 \times 10^5\) and \(\log L \leq 30\), this is sufficiently fast)
  • Space complexity: \(O(N)\)

Implementation Notes

  • Division of negative numbers: Integer division in C++ truncates toward zero, so a mathematical floor function (truncation toward negative infinity) must be implemented separately. The floor_div function in the code handles this.

  • Overflow prevention: \(V_i \cdot T\) can be as large as \(10^9 \times 10^9 = 10^{18}\), so long long is essential. The stamina \(P\) can also be up to \(10^{14}\).

  • Case \(k=0\): Not passing through any door (staying in place) is always possible, so the case mid == 0 in the binary search is handled specially.

    Source Code

#include <bits/stdc++.h>
using namespace std;

long long floor_div(long long a, long long b) {
    return a / b - (a % b != 0 && (a ^ b) < 0);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int N, Q;
    long long L;
    cin >> N >> L >> Q;
    
    vector<long long> A(N), R(N), V(N);
    for (int i = 0; i < N; i++) {
        cin >> A[i] >> R[i] >> V[i];
    }
    
    for (int j = 0; j < Q; j++) {
        long long T, S, P;
        cin >> T >> S >> P;
        
        vector<long long> C(N);
        for (int i = 0; i < N; i++) {
            C[i] = (R[i] + V[i] * T) % A[i];
        }
        
        // Compute total weight of doors in [lo, hi]
        auto total_weight = [&](long long lo, long long hi) -> long long {
            if (lo > hi) return 0;
            long long sum = 0;
            for (int i = 0; i < N; i++) {
                sum += floor_div(hi - C[i], A[i]) - floor_div(lo - 1 - C[i], A[i]);
            }
            return sum;
        };
        
        // Binary search right: find max k such that total_weight(S+1, S+k) <= P
        long long right_rooms = 0;
        {
            long long lo = 0, hi = L - 1 - S;
            while (lo <= hi) {
                long long mid = (lo + hi) / 2;
                if (mid == 0 || total_weight(S + 1, S + mid) <= P) {
                    right_rooms = mid;
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }
        }
        
        // Binary search left: find max k such that total_weight(S-k+1, S) <= P
        // Going left from room S by k rooms means passing through doors S, S-1, ..., S-k+1
        long long left_rooms = 0;
        {
            long long lo = 0, hi = S;
            while (lo <= hi) {
                long long mid = (lo + hi) / 2;
                if (mid == 0 || total_weight(S - mid + 1, S) <= P) {
                    left_rooms = mid;
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }
        }
        
        cout << left_rooms + right_rooms + 1 << "\n";
    }
    
    return 0;
}

This editorial was generated by claude4.6opus-thinking.