[R35C]平均数


对于 40%40\% 的数据,2n20002 \leq n \leq 2000

对于 100%100\% 的数据,2n2×1052 \leq n \leq 2 \times 10^51ai1091 \leq a_i \leq 10^9

思路

设数组元素之和为 S=k=1nakS = \sum_{k=1}^{n} a_k。对有序对 (i,j)(i, j)iji \neq j)执行一次操作后,数组总和变为 Sai+ajS - a_i + a_j。数组完美的充要条件是新总和能被 nn 整除,即:

(Sai+aj)modn=0(S - a_i + a_j) \bmod n = 0

移项得:

ajaiS(modn)a_j - a_i \equiv -S \pmod{n}

即:

ajaiS(modn)a_j \equiv a_i - S \pmod{n}

于是问题转化为同余计数。用 cnt[r]\text{cnt}[r] 表示满足 akmodn=ra_k \bmod n = r 的下标个数。对每个下标 ii,令:

target=((aiS)modn+n)modn\text{target} = ((a_i - S) \bmod n + n) \bmod n

则所有 ajmodn=targeta_j \bmod n = \text{target}jj 都满足条件,共有 cnt[target]\text{cnt}[\text{target}] 个。注意要排除 j=ij = i 的情况:当 aimodn=targeta_i \bmod n = \text{target} 时,ii 本身也被计入了一次,需要从答案中减去 11

对所有 ii 累加即得答案。

复杂度

  • 时间复杂度:O(n)O(n),两次遍历加一次计数。
  • 空间复杂度:O(n)O(n),用于存放计数数组。

仓颉实现

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

main(): Int64 {
    let reader = getStdIn()
    let n = Int64.parse(reader.readln().getOrThrow())
    let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
    var sum: Int64 = 0
    for (k in 0 .. n) {
        sum += a[k]
    }
    // cnt[r] = number of a_k with a_k % n == r
    let nn = n
    var cnt = Array<Int64>(nn, { _ => 0 })
    for (k in 0 .. n) {
        let r = ((a[k] % n) + n) % n
        cnt[r] += 1
    }
    var ans: Int64 = 0
    for (k in 0 .. n) {
        let target = (((a[k] - sum) % n) + n) % n
        ans += cnt[target]
        if ((((a[k] % n) + n) % n) == target) {
            ans -= 1
        }
    }
    println(ans)
    return 0
}