[R54C]切割圆
对于 的数据,,。
思路
环上共 个元素,一条直线切下后两部分各恰为 个连续元素,所以所有可能的切法就是枚举一个起点 ,取环上从 开始的连续 个元素作为一部分 ,剩余 个作为另一部分 。
设起点 对应的连续 元素之和为 ,整环总和为 ,则另一部分之和为 。目标是最大化:
所有切法只差在 上,而 随起点 每次右移一格,仅发生「减去离开窗口的 、加上进入窗口的 」的增量变化。因此用 滑动窗口 在 内求出全部 个 ,逐一计算异或值取最大即可。
复杂度
- 时间:,滑动窗口每个元素进出各一次。
- 空间:,存储 个数。
仓颉实现
import std.env.*
import std.convert.*
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) })
let m = n * 2
var total: Int64 = 0
for (i in 0..m) {
total += a[i]
}
// 滑动窗口大小为 n,初始窗口为 a[0..n-1]
var sum1: Int64 = 0
for (i in 0..n) {
sum1 += a[i]
}
var ans: Int64 = sum1 ^ (total - sum1)
var s: Int64 = 1
while (s < m) {
// 起点为 s 的窗口:减去 a[s-1],加上 a[(s+n-1) mod m]
let outIdx = s - 1
let inIdx = (s + n - 1) % m
sum1 = sum1 - a[outIdx] + a[inIdx]
let cur = sum1 ^ (total - sum1)
if (cur > ans) {
ans = cur
}
s++
}
println(ans)
return 0
}