[R49C]调整亮度

  • 难度 提高
  • 时限 1s
  • 空限 512m
  • 差分

数据规模:1n,Q2×1051 \le n, Q \le 2 \times 10^52hi92 \le h_i \le 91lrn1 \le l \le r \le n

思路

每盏灯的挡位变化只和它被拨动的总次数有关。由于第 ii 盏灯有 hih_i 个挡位,从 00 出发每拨动一次挡位加 11,到 hi1h_i - 1 后回到 00,等价于一个模 hih_i 的计数器。因此最终挡位就是该灯被拨动次数对 hih_i 取模。

关键在于快速求出每盏灯被覆盖的次数。每次操作给一个区间 [l,r][l, r],等价于把 [l,r][l, r] 内每盏灯的计数都加 11,这是典型的 区间加 问题。用差分数组:对每个 [l,r][l, r],令 diff[l] += 1diff[r+1] -= 1,最后做一次前缀和即可还原出每盏灯被拨动的次数 cnt[i]\text{cnt}[i]。最终答案为 cnt[i]modhi\text{cnt}[i] \bmod h_i

复杂度

时间 O(n+Q)O(n + Q),空间 O(n)O(n)

仓颉实现

import std.convert.*
import std.env.*

main(): Int64 {
    let reader = getStdIn()
    let firstLine = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
    let n = firstLine[0]
    let q = firstLine[1]
    let h = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
    let diff = Array<Int64>(n + 2, { _ => 0 })
    var i = 0
    while (i < q) {
        let line = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
        let l = line[0]
        let r = line[1]
        diff[l] = diff[l] + 1
        diff[r + 1] = diff[r + 1] - 1
        i++
    }
    let sb = StringBuilder()
    var cur = Int64(0)
    var j = 1
    while (j <= n) {
        cur = cur + diff[j]
        if (j > 1) {
            sb.append(" ")
        }
        sb.append(cur % h[j - 1])
        j++
    }
    println(sb.toString())
    return 0
}