[R53E] 异或求和
数据规模:。
思路
先求固定 对应的 。
设 是不超过 的最大的 的幂,并令
由于 的最高位为 , 和 在 对应的二进制位上必须恰好一个为 。先考虑 、 的情形,把 写成 。忽略这个最高位后,有
条件 等价于 。当 依次取 时, 被唯一确定;其中 会得到 ,不满足正整数条件,其余恰有 个合法数对。
交换 后还能得到另外 组,因此
接下来按最高二进制位分块求和。对于一个完整区间 , 依次为 ,所以
从 开始倍增,累加所有完整区间。若最后一个区间只到 ,令 ,其贡献为
所有乘法都先对 取模,避免中间结果溢出。
正确性证明
设 是不超过 的最大的 的幂,。
因为 ,并且 在 对应位上为 ,所以满足 的有序数对中,恰有一个数不小于 。固定 、,异或等式等价于 ,而 等价于 。每个 唯一对应一个 ,只有 时 不合法,所以这一方向恰有 对。交换两个数又得到 对,故 。
算法把 按形如 的区间划分,其中 是 的幂。在每个完整区间内,根据 ,算法累加的 正好等于该区间所有 之和;最后一个不完整区间同理,其贡献正好为 。这些区间不重不漏地覆盖 ,因此算法输出的就是 对 取模后的值。
复杂度
时间复杂度为 ,空间复杂度为 。
仓颉实现
import std.console.*
import std.convert.*
main(): Int64 {
let reader = Console.stdIn
let n = Int64.parse(reader.readln().getOrThrow())
let mod: Int64 = 1000000007
var answer: Int64 = 0
var highestBit: Int64 = 1
while (highestBit * 2 <= n) {
answer = (answer + highestBit % mod * ((highestBit - 1) % mod) % mod) % mod
highestBit *= 2
}
let remainder = n - highestBit
answer = (answer + remainder % mod * ((remainder + 1) % mod) % mod) % mod
println(answer)
return 0
}