LeetCode Entry
3655. XOR After Range Multiplication Queries II
Run stepped multiplication queries
3655. XOR After Range Multiplication Queries II hard blog post youtube

Join me on Telegram
https://t.me/leetcode_daily_unstoppable/1323
Problem TLDR
Run stepped multiplication queries #hard #mod
Intuition
Almost solved, gave up.
// same as yesterday
// i learned it before: split queries by sqrt(k)
// a^x = a^{2*(x/2 + x%2)} = (a*a)^{x/2}*(a*a)^{x%2}
// 18 minute, there is an error somewhere
// 28 minute, 2 errors fixes, still wrong answer
// nums =
//[2,3,1,5,4]
//queries =
//[[1,4,2,3],[0,2,1,2]]
// 4, 18, 2, 15, 4 -- expected
//
// 2, 3, 1, 5, 4
// 4, 6, 2, 5, 4 (after k=1 l..r=0..2 v=2)
// 4, 18, 6, 15, 12 -- mine (after k=2 l..r=1..4 v=3) (looks like i multiplied all without step)
// * *
// 42 minute: how to deal with step?
// 45 minute: another test case wrong 68/605
// 49 minute: i don't see any error in my code
//
// nums =
// [562,62]
// queries =
// [[0,1,2,7],[1,1,2,11],[0,1,2,2],[1,1,1,11],[1,1,2,1],[0,0,1,9],[0,1,2,4],[1,1,1,6],[0,0,2,17]]
// Output
// 591836426
// Expected
// 4839076
// 58 minute gave up.
- Divide problem on slow/fast path: k = sqrt(q) is the point of separation
- fast path is the big k steps, can be brute forced
- slow path: save events of start-stop for every k in p[k][l..r] individually
- collect them for every k separately
- modulo doesnt allow 1/v operation, have to use pow(v, M-2) instead
Approach
- my point of failure was the attention to one detail: when to cancel, it is not r+1, we have to use steps
- the threshold of 40: ~300ms vs 400: ~1300ms
Complexity
-
Time complexity: \(O(nsqrt(q))\)
-
Space complexity: \(O(nsqrt(q))\)
Code
// 323ms
fun xorAfterQueries(n: IntArray, q: Array<IntArray>): Int {
val p = Array(40) { IntArray(n.size+1){1} }; val M = 1_000_000_007L
fun pow(a: Long, b: Long): Long = if (b==0L) 1L else pow(a*a%M, b/2)*(if (b%2>0)a else 1L)%M
for ((l,r,k,v) in q)
if (k >= 40) for (i in l..r step k) n[i] = (1L*n[i]*v%M).toInt() else {
p[k][l] = (1L*p[k][l]*v%M).toInt(); val next = l + ((r-l)/k+1)*k
if (next < n.size) p[k][next] = (1L*p[k][next]*pow(1L*v, M-2L)%M).toInt()
}
for (k in 1..<40) for (i in n.indices) {
if (i >= k) p[k][i] = (1L*p[k][i]*p[k][i-k]%M).toInt()
n[i] = (1L*n[i]*p[k][i]%M).toInt()
}
return n.reduce(Int::xor)
}
// 322ms
pub fn xor_after_queries(mut n: Vec<i32>, q: Vec<Vec<i32>>) -> i32 {
const M: i64 = 1000000007; let z = n.len(); let mut c = vec![vec![1; z + 1]; 40];
fn p(a: i64, b: i64) -> i64 { if b < 1 { 1 } else { p(a * a % M, b / 2) * (if b % 2 > 0 { a } else { 1 }) % M } }
for u in q {
let (l, r, k, v) = (u[0] as usize, u[1] as usize, u[2] as usize, u[3] as i64);
if k < 40 { c[k][l] = c[k][l] * v % M; let x = r - (r - l) % k + k; if x < z { c[k][x] = c[k][x] * p(v, M - 2) % M } }
else { for i in (l..=r).step_by(k) { n[i] = (n[i] as i64 * v % M) as i32 } }
}
for k in 1..40 { for i in 0..z {
if i >= k { c[k][i] = c[k][i] * c[k][i - k] % M }
n[i] = (n[i] as i64 * c[k][i] % M) as i32;
}}
n.into_iter().fold(0, |a, b| a ^ b)
}