[R39C]网格求和
- 难度 提高
- 时限 1s
- 空限 512m
- 前缀和
对于 的数据,。
对于 的数据,,。
思路
对于每个 ,需要把第 行的所有格子和第 列的所有格子求和。第 行和第 列的并集里, 同时属于行和列,被加了两次,需要减去一次,即:
如果对每个 都暴力求和,复杂度是 ,无法承受。
预处理两个一维前缀和数组即可:
- :第 行的元素和;
- :第 列的元素和。
读入时顺便累加:每读入一个 ,累加到 与 。随后对每个 输出 。
注意值域:单个行列和最大为 , 最大约 ,超出 32 位整数范围,需要用 64 位整数。
复杂度
- 时间:读入 ,输出 ,总计 。
- 空间: 存储网格 ,另需 存行列和。
仓颉实现
import std.env.*
import std.convert.*
main(): Int64 {
let reader = getStdIn()
let first = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let n = first[0]
let m = first[1]
let nn = n
let mm = m
var a = Array<Array<Int64>>(nn, { _ => Array<Int64>(mm, { _ => 0 }) })
let rowSum = Array<Int64>(nn, { _ => 0 })
let colSum = Array<Int64>(mm, { _ => 0 })
for (i in 0..nn) {
let line = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
var rs = Int64(0)
for (j in 0..mm) {
a[i][j] = line[j]
rs += line[j]
colSum[j] += line[j]
}
rowSum[i] = rs
}
let sb = StringBuilder()
for (i in 0..nn) {
for (j in 0..mm) {
sb.append(rowSum[i] + colSum[j] - a[i][j])
if (j + 1 < mm) {
sb.append(" ")
}
}
sb.append("\n")
}
print(sb.toString())
return 0
}