题面
定义一个序列 a
:
an={1an−an−1+an−1−an−2n=1,2n≥3
记序列 a
的前缀和 si=k=1∑iak
。现共有 T
组数据,每组数据给定 k
,试求 sk
对 109+7
取模后的值。
数据范围:
1≤T≤105
1≤n≤1018
题目链接
分析
我们先对 ai
打个表吧(逃
前 10000 个值
我们观察这些值,不难发现从第 2
个值开始,1
出现了 1
次,2
出现了 2
次,3
出现了 1
次,4
出现了 3
次…… 好像所有奇数值只会出现 1
次,而能被 2
整除但不能被 4
整除的都出现 2
次,能被 4
整除但不能被 8
整除的都出现 3
次…… 如果我们结合每个数的二进制再观察一番就会发现,除 1
以外每个数 i
的出现次数 f(i)
都满足:
f(i)=log2(lowbit(i))+1
如果你不理解上面这个式子,你大可不必管它。你只需要知道:对于能被 2i
整除但不能被 2i+1
整除的数 i
,其 f(i)=i+1
。也就是说,f(i)
的值即 i
中含有质因子 2
的最大次数加 1
。
为了处理 1
这一特例,我们不妨把 a1
扔掉,然后把 ai
看作 ai−1
。最后再在答案上加 1
。
现在我们不妨把出现了 f(i)
次的 i
都看成一个长度为 f(i)
的块。直观地说,就是把原序列这样划分:
[1], [2,2], [3], [4,4,4], [5], [6,6], [7], [8,8,8], …
那么前 k
个数里面应该会有 t
个这样完整的块,另外最后可能还有一个不完整的块。我们需要求的 sk
,也就是前面完整块的和,再加上最后一个不完整块的和(如果有的话)。
前 t
个完整块的和:
i=1∑t(i⋅f(i))
前 t
个完整块一共包含数的个数:
i=1∑tf(i)
所以剩余数的个数:
k−i=1∑tf(i)
我们知道这个剩余的不完整的块中所有的数都是 t+1
,所以不完整块的和:
(t+1)⋅(k−i=1∑tf(i))
加起来便有:
sk=i=1∑t(i⋅f(i))+(t+1)⋅(k−i=1∑tf(i))
如何确定 t
的值呢?我们可以考虑二分答案把求解转为判定。
再次温习一遍 f(i)
的规律:对于能被 2i
整除但不能被 2i+1
整除的数 i
,有 f(i)=i+1
。
于是我们不难得出:
i=1∑tf(i)=⌊20t⌋+⌊21t⌋+⌊22t⌋+…
我们不妨把 f
想象成一堆桶。刚开始时对于所有数都有 f(i)=0
。在上面的式子中,⌊20t⌋
相当于给所有能被 20
数的 f
都加了 1
,⌊21t⌋
相当于给所有能被 21
整除的数的 f
都加了 1
,…… 也就是说,能被 2i
整除但不能被 2i+1
整除的数的 f
都被加了 i+1
次 1
。
另外二分时要注意两点:
- 不可以直接用等比数列求和公式,因为每一项都向下取整了;
- 关于答案范围:通过前面的表可以观察到 t
的值一般在 2k
左右,且很多时候略大于 2k
,故
为了卡进时限可以将二分范围确立为 [2k−1,2k+50]
。
至于前 t
个完整块的求和,我们不难发现如下规律:
- 出现次数为 1
的数:1, 3, 5, 7, 9, …
是个首项为 20
,公差为 21
的等差数列。
- 出现次数为 2
的数:2, 6, 10, 14, 18, …
进一步,可化为:21×(1, 3, 5, 7, 9, …)
- 出现次数为 3
的数:4, 12, 20, 28, 36, …
进一步,可化为:22×(1, 3, 5, 7, 9, …)
- …
- 出现次数为 i
的数:2i−1×(1, 3, 5, 7, 9, …)
所以我们用等差数列求和公式即可得解。
至此,关键问题就都解决了。
实现
完整参考代码
%%%