[R53E] 异或求和


数据规模:1n10181 \le n \le 10^{18}

思路

先求固定 xx 对应的 f(x)f(x)

pp 是不超过 xx 的最大的 22 的幂,并令

x=p+r,0r<px=p+r,\qquad 0\le r<p。

由于 AB=xA\oplus B=x 的最高位为 11AABBpp 对应的二进制位上必须恰好一个为 11。先考虑 A<pA<pBpB\ge p 的情形,把 BB 写成 p+bp+b。忽略这个最高位后,有

Ab=rA\oplus b=r。

条件 BxB\le x 等价于 brb\le r。当 bb 依次取 0,1,,r0,1,\ldots,r 时,A=brA=b\oplus r 被唯一确定;其中 b=rb=r 会得到 A=0A=0,不满足正整数条件,其余恰有 rr 个合法数对。

交换 A,BA,B 后还能得到另外 rr 组,因此

f(x)=2r=2(xp)f(x)=2r=2(x-p)。

接下来按最高二进制位分块求和。对于一个完整区间 [p,2p1][p,2p-1]rr 依次为 0,1,,p10,1,\ldots,p-1,所以

x=p2p1f(x)=2r=0p1r=p(p1)\sum_{x=p}^{2p-1}f(x) =2\sum_{r=0}^{p-1}r =p(p-1)。

p=1p=1 开始倍增,累加所有完整区间。若最后一个区间只到 nn,令 m=npm=n-p,其贡献为

2r=0mr=m(m+1)2\sum_{r=0}^{m}r=m(m+1)。

所有乘法都先对 109+710^9+7 取模,避免中间结果溢出。

正确性证明

pp 是不超过 xx 的最大的 22 的幂,x=p+rx=p+r

因为 A,Bx<2pA,B\le x<2p,并且 xxpp 对应位上为 11,所以满足 AB=xA\oplus B=x 的有序数对中,恰有一个数不小于 pp。固定 A<pA<pB=p+bB=p+b,异或等式等价于 A=brA=b\oplus r,而 BxB\le x 等价于 brb\le r。每个 b[0,r]b\in[0,r] 唯一对应一个 AA,只有 b=rb=rA=0A=0 不合法,所以这一方向恰有 rr 对。交换两个数又得到 rr 对,故 f(x)=2rf(x)=2r

算法把 [1,n][1,n] 按形如 [p,2p1][p,2p-1] 的区间划分,其中 pp22 的幂。在每个完整区间内,根据 f(x)=2(xp)f(x)=2(x-p),算法累加的 p(p1)p(p-1) 正好等于该区间所有 f(x)f(x) 之和;最后一个不完整区间同理,其贡献正好为 m(m+1)m(m+1)。这些区间不重不漏地覆盖 [1,n][1,n],因此算法输出的就是 i=1nf(i)\sum_{i=1}^{n}f(i)109+710^9+7 取模后的值。

复杂度

时间复杂度为 O(logn)O(\log n),空间复杂度为 O(1)O(1)

仓颉实现

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
}