AFOI-19 sum与prod 题解

题目传送门

题目大意: ∑ i = 1 2 n log ⁡ 2 ( ∏ j = 1 i l o w b i t ( j ) ) \sum_{i=1}^{2^n}\log_2(\prod_{j=1}^i lowbit(j)) i=12nlog2(j=1ilowbit(j))

废话

这场比赛比较晚打,所以只看了前两题,然后因为这第二题也比较毒瘤,所以做完之后比赛就结束了。

但是令我游戏体验爆炸的是,在我推出正解提交的那一刻,洛谷评测机炸了:(

没错,在两分钟前还没有炸:(
在这里插入图片描述
然后我第二题就只有 47 47 47的好成绩了。

题解

怎么看都不是绿题的亚子啊qwq

可能是我的做法太不优秀了……

我们先考虑求后面的那一串 ∏ j = 1 i l o w b i t ( j ) \prod_{j=1}^i lowbit(j) j=1ilowbit(j)

既然有 l o w b i t lowbit lowbit,那么肯定会想到树状数组嘛,那么我们考虑找找规律什么的,先摆一个树状数组出来:
在这里插入图片描述
我们惊奇地发现,对于一个 l o w b i t lowbit lowbit 2 x 2^x 2x 的点,他管理的区间的所有点的 l o w b i t lowbit lowbit 的积恰好就是 2 2 x − 1 2^{2^x-1} 22x1。比如说绿色点,它的 l o w b i t lowbit lowbit 2 2 2^2 22,然后他管理的区间的 l o w b i t lowbit lowbit 之积就是 2 3 2^3 23

然后会发现,这个证明其实也很简单,我们设 f i f_i fi 表示 l o w b i t lowbit lowbit 2 i 2^i 2i 的节点管理区间内的 l o w b i t lowbit lowbit 之积。那么可以得到 f i = 2 f i − 1 2 f_i=2f_{i-1}^2 fi=2fi12,以上图中绿色节点往蓝色节点转移为例,会发现其实绿色节点管理的 1 1 1 ~ 3 3 3 区间和蓝色节点管理的 5 5 5 ~ 7 7 7 区间是一样的,不同的只有蓝色节点比绿色节点的 l o w b i t lowbit lowbit 要大一倍,所以蓝色节点管理的区间等价于将绿色节点管理的区间复制一份,然后将复制的一份中的最后一个节点的 l o w b i t lowbit lowbit 翻一倍,所以转移就是 2 f i − 1 2 2f_{i-1}^2 2fi12

因为 f i f_i fi 必然是一个 2 2 2 的幂,我们不妨用 2 c i 2^{c_i} 2ci 来表示它,那么转移方程又可以表示成: 2 c i = 2 c i − 1 × 2 + 1 2^{c_i}=2^{c_{i-1}\times2+1} 2ci=2ci1×2+1,因为 f 0 = 2 0 f_0=2^0 f0=20,即 c 0 c_0 c0 等于 0 0 0,所以显然有 c i = 2 i − 1 c_i=2^i-1 ci=2i1

所以这个 ∏ j = 1 i l o w b i t ( j ) \prod_{j=1}^i lowbit(j) j=1ilowbit(j) 我们可以考虑写成像树状数组求前缀和那样的形式:
∏ j = 1 i l o w b i t ( j ) = ∏ k = 0 p f k [ i   a n d   2 k > 0 ] = ∏ k = 0 p 2 c i [ i   a n d   2 k > 0 ] = ∏ k = 0 p 2 2 i − 1 [ i   a n d   2 k > 0 ] \begin{aligned} \prod_{j=1}^i lowbit(j)&=\prod_{k=0}^p f_k[i~and~2^k>0]\\ &=\prod_{k=0}^p 2^{c_i}[i~and~2^k>0]\\ &=\prod_{k=0}^p 2^{2^i-1}[i~and~2^k>0] \end{aligned} j=1ilowbit(j)=k=0pfk[i and 2k>0]=k=0p2ci[i and 2k>0]=k=0p22i1[i and 2k>0]

其中, a n d and and运算, p p p i i i 的二进制下的位数。

带回去原柿子,得到:
∑ i = 1 2 n log ⁡ 2 ( ∏ k = 0 n 2 2 i − 1 [ i   a n d   2 k > 0 ] ) = ∑ i = 1 2 n ∑ k = 0 n 2 i − 1 [ i   a n d   2 k > 0 ] \begin{aligned} &\sum_{i=1}^{2^n}\log_2(\prod_{k=0}^n 2^{2^i-1}[i~and~2^k>0])\\ &=\sum_{i=1}^{2^n}\sum_{k=0}^n 2^i-1[i~and~2^k>0] \end{aligned} i=12nlog2(k=0n22i1[i and 2k>0])=i=12nk=0n2i1[i and 2k>0]

然而,现在还是不怎么可做,内外层两个循环我们半个都枚举不了……

但是里面的循环的上限是 n n n,比较小,我们考虑把它提出来:
∑ k = 0 n ∑ i = 1 2 n 2 i − 1 [ i   a n d   2 k > 0 ] \sum_{k=0}^n \sum_{i=1}^{2^n}2^i-1[i~and~2^k>0] k=0ni=12n2i1[i and 2k>0]

那么现在就是考虑 1 1 1 ~ 2 n 2^n 2n 这些数在每一个二进制位上的贡献。

考虑到在同一位上的贡献其实都是一样的,所以我们只需要考虑每一位上有多少个数不为 0 0 0

依然考虑推柿子:设 f ( i ) f(i) f(i) 表示区间 1 1 1 ~ 2 i − 1 2^i-1 2i1 中所有数的贡献和。

那么 f ( i ) f(i) f(i) 转移到 f ( i + 1 ) f(i+1) f(i+1),相当于多了 2 i 2^i 2i ~ 2 i + 1 − 1 2^{i+1}-1 2i+11 这些数,然而我们发现一个奇妙的规律: 2 i + 1 2^i+1 2i+1 ~ 2 i + 1 − 1 2^{i+1}-1 2i+11 这些数相当于 1 1 1 ~ 2 i − 1 2^i-1 2i1 这些数每个数加上 2 i 2^i 2i。所以这些数的贡献等于 f ( i ) + ( 2 i + 1 − 1 − 2 i − 1 + 1 ) × ( 2 i − 1 ) = f ( i ) + ( 2 i − 1 ) 2 f(i)+(2^{i+1}-1-2^i-1+1)\times (2^i-1)=f(i)+(2^i-1)^2 f(i)+(2i+112i1+1)×(2i1)=f(i)+(2i1)2

最后把 2 i 2^i 2i 这个数算上,它的贡献是 2 i − 1 2^i-1 2i1,所以递推式为:
f ( i + 1 ) = f ( i ) + f ( i ) + ( 2 i − 1 ) 2 + 2 i − 1 = 2 f ( i ) + ( 2 i − 1 ) × 2 i = 2 f ( i ) + 2 2 i − 2 i = 2 f ( i ) + 4 i − 2 i \begin{aligned} f(i+1)&=f(i)+f(i)+(2^i-1)^2+2^i-1\\ &=2f(i)+(2^i-1)\times 2^i\\ &=2f(i)+2^{2i}-2^i\\ &=2f(i)+4^i-2^i\\ \end{aligned} f(i+1)=f(i)+f(i)+(2i1)2+2i1=2f(i)+(2i1)×2i=2f(i)+22i2i=2f(i)+4i2i

即:
f ( i ) = 2 f ( i − 1 ) + 4 i − 1 − 2 i − 1 f(i)=2f(i-1)+4^{i-1}-2^{i-1} f(i)=2f(i1)+4i12i1

其中,根据上面的定义,显然有 f ( 1 ) = 0 f(1)=0 f(1)=0

所以最后的答案就是 f ( n ) + 2 n − 1 f(n)+2^n-1 f(n)+2n1,因为 f ( n ) f(n) f(n) 只考虑了 1 1 1 ~ 2 n − 1 2^n-1 2n1 的贡献,最后还要加上 2 n 2^n 2n 的贡献。那么现在已经得到一个 O ( n ) O(n) O(n) 50 50 50 分做法了。

但是我们当然要追求 100 100 100 分,所以考虑求这个递推式的通项公式。

接下来的内容可能引起不适,请务必保证你学过OGF

接下来我们考虑用生成函数来求通项公式:设 F ( x ) = ∑ i = 1 f ( i ) x i F(x)=\sum_{i=1} f(i)x^i F(x)=i=1f(i)xi

因为没有第 0 0 0 项比较麻烦,我们考虑将 F ( x ) F(x) F(x) 的系数整体左移一位,也就是: F ( x ) = ∑ i = 0 f ( i + 1 ) x i F(x)=\sum_{i=0}f(i+1)x_i F(x)=i=0f(i+1)xi

整体左移一位之后, f f f 的递推式变成 f ( i ) = 2 f ( i − 1 ) + 4 i − 2 i f(i)=2f(i-1)+4^i-2^i f(i)=2f(i1)+4i2i,其中 f ( 0 ) = 0 f(0)=0 f(0)=0

那么根据递推式,我们可以得到:
F = 2 F x + 1 1 − 4 x − 1 1 − 2 x F ( 1 − 2 x ) = 1 1 − 4 x − 1 1 − 2 x F = 1 ( 1 − 4 x ) ( 1 − 2 x ) − 1 ( 1 − 2 x ) 2 \begin{aligned} F&=2Fx+\frac 1 {1-4x}-\frac 1 {1-2x}\\ F(1-2x)&=\frac 1 {1-4x}-\frac 1 {1-2x}\\ F&=\frac 1 {(1-4x)(1-2x)}-\frac 1 {(1-2x)^2}\\ \end{aligned} FF(12x)F=2Fx+14x112x1=14x112x1=(14x)(12x)1(12x)21

发现里面的 1 ( 1 − 4 x ) ( 1 − 2 x ) \frac 1 {(1-4x)(1-2x)} (14x)(12x)1 无法展开,于是考虑裂项


A 1 − a x + B 1 − b x = 1 ( 1 − 4 x ) ( 1 − 2 x ) \frac A {1-ax}+\frac B {1-bx}=\frac 1 {(1-4x)(1-2x)} 1axA+1bxB=(14x)(12x)1,那么有:
A − b x A + B − a x B ( 1 − a x ) ( 1 − b x ) = 1 ( 1 − 4 x ) ( 1 − 2 x ) \frac {A-bxA+B-axB} {(1-ax)(1-bx)}=\frac 1 {(1-4x)(1-2x)} (1ax)(1bx)AbxA+BaxB=(14x)(12x)1

那么根据这两个柿子的分母,显然有:
{ a = 4 b = 2 \begin{cases} a=4\\ b=2 \end{cases} {a=4b=2

带入到分子中,有:
A − 2 x A + B − 4 x B = 1 ( A + B ) − ( 2 A + 4 B ) x = 1 \begin{aligned} A-2xA+B-4xB&=1\\ (A+B)-(2A+4B)x&=1 \end{aligned} A2xA+B4xB(A+B)(2A+4B)x=1=1

那么可以列出方程:
{ A + B = 1 2 A + 4 B = 0 \begin{cases} A+B=1\\ 2A+4B=0 \end{cases} {A+B=12A+4B=0

解得:
{ A = 2 B = − 1 \begin{cases} A=2\\ B=-1 \end{cases} {A=2B=1


带回去有:
F = 2 1 − 4 x − 1 1 − 2 x − 1 ( 1 − 2 x ) 2 F=\frac 2 {1-4x}-\frac 1 {1-2x}-\frac 1 {(1-2x)^2} F=14x212x1(12x)21

大力展开,有:
∑ i = 0 ( 2 × 4 i − 2 i − C i + 2 − 1 2 − 1 2 i ) x i = ∑ i = 0 ( 2 × 4 i − 2 i − ( i + 1 ) 2 i ) x i \begin{aligned} &\sum_{i=0} (2\times 4^i-2^i-C_{i+2-1}^{2-1}2^i)x^i\\ &=\sum_{i=0} (2\times 4^i-2^i-(i+1)2^i)x^i \end{aligned} i=0(2×4i2iCi+21212i)xi=i=0(2×4i2i(i+1)2i)xi

因为我们一开始将系数整体左移了一位,所以我们现在需要的是 x n − 1 x^{n-1} xn1 项的系数而不是 x n x^n xn 的系数,所以答案为:
2 × 4 n − 1 − 2 n − 1 − n 2 n − 1 + 2 n − 1 2\times 4^{n-1}-2^{n-1}-n2^{n-1}+2^n-1 2×4n12n1n2n1+2n1

代码如下(需要注意取模):

#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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值