Update
- dp 式没有使用函数形式,否则会与生成函数混淆,请注意。
前言
手推了好久柿子才推出来,结果最后一步不会,最后看了题解才知道是倍增。
所以,这算一个教训吧。
思路
以下默认 b0=0。
首先 n>k 显然无解,原理是每次 n 加一必然多至少一位值为 1。
我们设 fn,k 为恰好占用了 k 个二进制位时长度为 n 的序列的方案数。特别的,n>k 时 fn,k=0。
由定义,我们有
ans=∑i=0k(ik)fn,i
我们发现一个 dp 式:
fn,k=∑i=0k−1(ik)2ifn−1,i
为啥我感觉这个很难想啊(因为我最开始没加这个二项式系数,推了 114514 秒后得到了一个假柿子),简要说说原理:
- 枚举 bn−1 已经占有的位数 i(fn−1,i),同时枚举是哪 i 位((ik)),那么这 i 位 an 既可占有亦可不占有(2i)。
- 此外 k−i 位必须占有。
然后,设 EGF:
f^n(x)=∑k=0+∞fn,kk!xk
那么:
f^n(x)=∑k=0+∞k!xk∑i=0k−1i!×(k−i)!k!2i[i!xi]f^n−1(x)
=∑k=0+∞xk∑i=0k−1(k−i)!1×i!2i[i!xi]f^n−1(x)
=∑k=0+∞xk∑i=0k−1(k−i)!1[xi]f^n−1(2x)
=∑i=0+∞xi[xi]f^n−1(2x)∑k=i+1+∞xk−i(k−i)!1
=∑i=0+∞xi[xi]f^n−1(2x)∑k=1+∞k!xk
=(ex−1)∑i=0+∞xi[xi]f^n−1(2x)
=(ex−1)f^n−1(2x)
即,f^n(x)=(expx−1)f^n−1(2x)。
边界 f^0(x)=1。
展开来,我们有
f^n(x)=∏i=0n−1(e2ix−1)
而我们要求的,就是
ans=∑i=0k(ik)[i!xi]f^n(x)=k!∑i=0k(k−i)![xi]f^n(x)
因此只要能卷出 fn(x)modxk+1 就可得答案。
由展开式,我们有:
f^2n(x)=f^n(x)×f^n(2nx)
又有
f^2n+1(x)=f^2n(x)×(e22nx−1)
于是可以倍增或者递归卷出 f^n(x)。我采用了后者。
时间复杂度:
T(n)=T(2n)+O(nlogn)=O(nlogn)
Code
模数 1000000007 太吐了,要 MTT。
代码太长了,扔剪贴板里了。
链接。
核心代码的伪代码:
Integer n, k
poly f(Integer n)
if n == 1
poly ans = "x"
ans = exp(ans) - 1
Make deg(ans) = k
return ans
poly ans, g
g = f(n/2)
ans = g
Modint w, p
w = pow(2, n/2)
p = 1
for Integer i from 0 to k
g[i] = g[i] * p
p = p * w
ans = ans * g
Make deg(ans) = k
if n % 2 == 1
g = pow(2, n/2) * "x"
g = exp(g) - 1
Make deg(g) = k
ans = ans * g
Make deg(ans) = k
return ans
main()
Input n, k
if n > k
Output 0
return
poly w = f(n)
Modint ans
ans = 0
for Integer i from n to k
ans = ans + Inv((k-i)!) * w[i]
ans = ans * k!
Output ans
总结
开头说了,我没有想到倍增。
这题说明了如何快速卷出出自倍增式的多项式组的指定项。
这确实算是一个教训吧。