题目传送门
题目大意: 求
∑i=12nlog2(∏j=1ilowbit(j))。
废话
这场比赛比较晚打,所以只看了前两题,然后因为这第二题也比较毒瘤,所以做完之后比赛就结束了。
但是令我游戏体验爆炸的是,在我推出正解提交的那一刻,洛谷评测机炸了:(
没错,在两分钟前还没有炸:(
然后我第二题就只有
47 分的好成绩了。
题解
怎么看都不是绿题的亚子啊qwq
可能是我的做法太不优秀了……
我们先考虑求后面的那一串
∏j=1ilowbit(j)。
既然有
lowbit,那么肯定会想到树状数组嘛,那么我们考虑找找规律什么的,先摆一个树状数组出来:
我们惊奇地发现,对于一个
lowbit 为
2x 的点,他管理的区间的所有点的
lowbit 的积恰好就是
22x−1。比如说绿色点,它的
lowbit 是
22,然后他管理的区间的
lowbit 之积就是
23。
然后会发现,这个证明其实也很简单,我们设
fi 表示
lowbit 为
2i 的节点管理区间内的
lowbit 之积。那么可以得到
fi=2fi−12,以上图中绿色节点往蓝色节点转移为例,会发现其实绿色节点管理的
1 ~
3 区间和蓝色节点管理的
5 ~
7 区间是一样的,不同的只有蓝色节点比绿色节点的
lowbit 要大一倍,所以蓝色节点管理的区间等价于将绿色节点管理的区间复制一份,然后将复制的一份中的最后一个节点的
lowbit 翻一倍,所以转移就是
2fi−12。
因为
fi 必然是一个
2 的幂,我们不妨用
2ci 来表示它,那么转移方程又可以表示成:
2ci=2ci−1×2+1,因为
f0=20,即
c0 等于
0,所以显然有
ci=2i−1。
所以这个
∏j=1ilowbit(j) 我们可以考虑写成像树状数组求前缀和那样的形式:
j=1∏ilowbit(j)=k=0∏pfk[i and 2k>0]=k=0∏p2ci[i and 2k>0]=k=0∏p22i−1[i and 2k>0]
其中,
and 是与运算,
p 是
i 的二进制下的位数。
带回去原柿子,得到:
i=1∑2nlog2(k=0∏n22i−1[i and 2k>0])=i=1∑2nk=0∑n2i−1[i and 2k>0]
然而,现在还是不怎么可做,内外层两个循环我们半个都枚举不了……
但是里面的循环的上限是
n,比较小,我们考虑把它提出来:
k=0∑ni=1∑2n2i−1[i and 2k>0]
那么现在就是考虑
1 ~
2n 这些数在每一个二进制位上的贡献。
考虑到在同一位上的贡献其实都是一样的,所以我们只需要考虑每一位上有多少个数不为
0。
依然考虑推柿子:设
f(i) 表示区间
1 ~
2i−1 中所有数的贡献和。
那么
f(i) 转移到
f(i+1),相当于多了
2i ~
2i+1−1 这些数,然而我们发现一个奇妙的规律:
2i+1 ~
2i+1−1 这些数相当于
1 ~
2i−1 这些数每个数加上
2i。所以这些数的贡献等于
f(i)+(2i+1−1−2i−1+1)×(2i−1)=f(i)+(2i−1)2。
最后把
2i 这个数算上,它的贡献是
2i−1,所以递推式为:
f(i+1)=f(i)+f(i)+(2i−1)2+2i−1=2f(i)+(2i−1)×2i=2f(i)+22i−2i=2f(i)+4i−2i
即:
f(i)=2f(i−1)+4i−1−2i−1
其中,根据上面的定义,显然有
f(1)=0。
所以最后的答案就是
f(n)+2n−1,因为
f(n) 只考虑了
1 ~
2n−1 的贡献,最后还要加上
2n 的贡献。那么现在已经得到一个
O(n) 的
50 分做法了。
但是我们当然要追求
100 分,所以考虑求这个递推式的通项公式。
接下来的内容可能引起不适,请务必保证你学过OGF。
接下来我们考虑用生成函数来求通项公式:设
F(x)=∑i=1f(i)xi。
因为没有第
0 项比较麻烦,我们考虑将
F(x) 的系数整体左移一位,也就是:
F(x)=∑i=0f(i+1)xi。
整体左移一位之后,
f 的递推式变成
f(i)=2f(i−1)+4i−2i,其中
f(0)=0。
那么根据递推式,我们可以得到:
FF(1−2x)F=2Fx+1−4x1−1−2x1=1−4x1−1−2x1=(1−4x)(1−2x)1−(1−2x)21
发现里面的
(1−4x)(1−2x)1 无法展开,于是考虑裂项。
设
1−axA+1−bxB=(1−4x)(1−2x)1,那么有:
(1−ax)(1−bx)A−bxA+B−axB=(1−4x)(1−2x)1
那么根据这两个柿子的分母,显然有:
{a=4b=2
带入到分子中,有:
A−2xA+B−4xB(A+B)−(2A+4B)x=1=1
那么可以列出方程:
{A+B=12A+4B=0
解得:
{A=2B=−1
带回去有:
F=1−4x2−1−2x1−(1−2x)21
大力展开,有:
i=0∑(2×4i−2i−Ci+2−12−12i)xi=i=0∑(2×4i−2i−(i+1)2i)xi
因为我们一开始将系数整体左移了一位,所以我们现在需要的是
xn−1 项的系数而不是
xn 的系数,所以答案为:
2×4n−1−2n−1−n2n−1+2n−1
代码如下(需要注意取模):
#include <cstdio>
#include <cstring>
#define mod 1000000007
#define ll long long
ll n;
ll ksm(ll x,ll y)
{
ll re=1,tot=x;
while(y)
{
if(y&1)re=re*tot%mod;
tot=tot*tot%mod;
y>>=1;
}
return re;
}
int main()
{
scanf("%lld",&n);n--;
printf("%lld",(((2*ksm(4,n)%mod-ksm(2,n)+mod)%mod-(n+1)%mod*ksm(2,n)%mod+mod)%mod+ksm(2,n+1)-1+mod)%mod);
}