[R3F] 平均数和

  • 难度 提高
  • 时限 1s
  • 空限 512m
  • 树状数组离散化前缀和

数据规模:1n5×1051 \le n \le 5 \times 10^51Ai,x2×1061 \le A_i,x \le 2 \times 10^6

思路

Bi=AixB_i = A_i - x,则 avg(l,r)x    i=lrBi0avg(l,r) \ge x \iff \sum_{i=l}^r B_i \ge 0。设 SBSBSASA 分别为 BBAA 的前缀和,条件等价于 SB(r)SB(l1)SB(r) \ge SB(l-1)

枚举右端点 rr,满足条件的左端点 ll 对应 j=l1[0,r1]j = l-1 \in [0, r-1]SB(j)SB(r)SB(j) \le SB(r)。区间和 SA(r)SA(j)SA(r) - SA(j) 对答案的总贡献为:

j(SA(r)SA(j))=SA(r)×cntjSA(j)\sum_{j} (SA(r) - SA(j)) = SA(r) \times cnt - \sum_j SA(j)

其中 cntcntjSA(j)\sum_j SA(j) 分别是满足 SB(j)SB(r)SB(j) \le SB(r)jj 的数量与 SASA 之和。把 SBSB 值离散化后用两棵 树状数组 分别维护这两个量,每步先插入 j=r1j = r-1 再查询。

复杂度:时间 O(nlogn)O(n \log n),空间 O(n)O(n)

仓颉实现

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

const MOD = 998244353

func bitAdd(bit: Array<Int64>, pos: Int64, delta: Int64, size: Int64) {
    var i = pos
    while (i <= size) {
        bit[i] += delta
        i += i & (-i)
    }
}

func bitSum(bit: Array<Int64>, pos: Int64): Int64 {
    var s: Int64 = 0
    var i = pos
    while (i > 0) {
        s += bit[i]
        i -= i & (-i)
    }
    return s
}

// 在已排序 vals 中找第一个 >= v 的位置(1-based)
func lowerBound(vals: Array<Int64>, v: Int64): Int64 {
    var lo: Int64 = 0
    var hi: Int64 = vals.size
    while (lo < hi) {
        let mid = (lo + hi) / 2
        if (vals[mid] < v) {
            lo = mid + 1
        } else {
            hi = mid
        }
    }
    return lo + 1
}

main(): Int64 {
    let reader = getStdIn()
    let nx = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p => Int64.parse(p) })
    let n = nx[0]
    let x = nx[1]
    let nn = n
    let arr = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p => Int64.parse(p) })
    var sa = Array<Int64>(nn + 1, { _ => 0 })
    var sb = Array<Int64>(nn + 1, { _ => 0 })
    var accA: Int64 = 0
    var accB: Int64 = 0
    for (i in 1..=nn) {
        let v = arr[i - 1]
        accA += v
        accB += v - x
        sa[i] = accA
        sb[i] = accB
    }
    // 离散化 SB
    var vals = Array<Int64>(nn + 1, { _ => 0 })
    for (i in 0..=nn) {
        vals[i] = sb[i]
    }
    sort(vals)
    var rank = Array<Int64>(nn + 1, { _ => 0 })
    for (i in 0..=nn) {
        rank[i] = lowerBound(vals, sb[i])
    }
    let m = nn + 1
    var cntBit = Array<Int64>(m + 1, { _ => 0 })
    var sumBit = Array<Int64>(m + 1, { _ => 0 })
    var ans: Int64 = 0
    for (r in 1..=nn) {
        let j = r - 1
        bitAdd(cntBit, rank[j], 1, m)
        bitAdd(sumBit, rank[j], sa[j] % MOD, m)
        let c = bitSum(cntBit, rank[r])
        let s = bitSum(sumBit, rank[r])
        ans = (ans + (sa[r] % MOD) * (c % MOD) - s) % MOD
        if (ans < 0) {
            ans += MOD
        }
    }
    println(ans)
    return 0
}

要点:

  • SA(r)SA(r) 可达 101210^{12},前缀和数组用 Int64;答案按模 998244353998244353 计算,树状数组里存 SA(j)modMODSA(j) \bmod MOD 即可。
  • 比较 avgxavg \ge xSB(r)SB(j)SB(r) \ge SB(j) 的整数比较,避免浮点。
  • 每轮先插入 j=r1j = r-1 再查询,保证只统计 jr1j \le r-1(即非空区间)。