Problem Description
Design and implement a Fancy Sequence class that maintains a list of numbers with three update operations and one query operation. The API supports:
- append(val): Append an integer val to the sequence.
- addAll(inc): Add inc to every element in the sequence.
- multAll(m): Multiply every element in the sequence by m.
- getIndex(idx): Return the element at index idx (0-based) under modulo 10^9+7 transformation. If idx is out of bounds, return -1.
All operations must be efficient, even though multiple sequential transformations are applied across the sequence.
Key Insights
- Instead of updating every element for addAll and multAll operations, maintain two global transformation parameters: a multiplicative factor and an additive offset.
- For each appended element, record the current transformation state so that later adjustments can be computed relative to when the element was added.
- For getIndex, use modular arithmetic along with the modular multiplicative inverse (Fermat’s little theorem) to “reverse” the effect of the transformation recorded at insertion.
- This lazy propagation strategy allows each operation to run in O(1) time.
Space and Time Complexity
Time Complexity: O(1) per operation. Space Complexity: O(n), where n is the number of appended elements.
Solution
We maintain two global variables: prod (initially 1) and add (initially 0). Every time addAll(inc) or multAll(m) is called, we update these parameters to represent the cumulative effect of the operations on all elements. For each element appended, we record its value along with the state (prod, add) at the time of append. When getIndex(idx) is called, we “reverse” the transformation that was in place at append time by computing a ratio factor using the modular inverse. This lets us calculate the current value using the formula:
result = (val * (globalProd / recordedProd) + (globalAdd – recordedAdd * (globalProd / recordedProd))) mod MOD
Modular arithmetic is used throughout to handle the modulo 10^9+7 requirement.