同见于我的洛谷博客


Update

  • dp 式没有使用函数形式,否则会与生成函数混淆,请注意。

前言

手推了好久柿子才推出来,结果最后一步不会,最后看了题解才知道是倍增。

所以,这算一个教训吧


思路

以下默认 b0=0b_0=0b0=0

首先 n>kn>kn>k 显然无解,原理是每次 nnn 加一必然多至少一位值为 111

我们设 fn,kf_{n,k}fn,k恰好占用了 kkk 个二进制位时长度为 nnn 的序列的方案数。特别的,n>kn>kn>kfn,k=0f_{n,k}=0fn,k=0

由定义,我们有

ans=i=0k(ki)fn,ians=\sum_{i=0}^{k}\binom kif_{n,i}ans=i=0k(ik)fn,i

我们发现一个 dp 式:

fn,k=i=0k1(ki)2ifn1,if_{n,k}=\sum_{i=0}^{k-1}\binom ki2^if_{n-1,i}fn,k=i=0k1(ik)2ifn1,i

为啥我感觉这个很难想啊(因为我最开始没加这个二项式系数,推了 114514114514114514 秒后得到了一个假柿子),简要说说原理:

  • 枚举 bn1b_{n-1}bn1 已经占有的位数 iiifn1,if_{n-1,i}fn1,i),同时枚举是哪 iii 位((ki)\binom ki(ik)),那么这 iiiana_nan 既可占有亦可不占有(2i2^i2i)。
  • 此外 kik-iki 位必须占有。

然后,设 EGF\operatorname{EGF}EGF

<mover accent="true">f^</mover>n(x)=k=0+fn,kxkk!\hat f_n(x)=\sum_{k=0}^{+\infty}f_{n,k}{x^k\over k!}f^n(x)=k=0+fn,kk!xk

那么:

<mover accent="true">f^</mover>n(x)=k=0+xkk!i=0k1k!i!×(ki)!2i[xii!]<mover accent="true">f^</mover>n1(x)\hat f_n(x)=\sum_{k=0}^{+\infty}{x^k\over k!}\sum_{i=0}^{k-1}{k!\over i!\times(k-i)!}2^i[{x^i\over i!}]\hat f_{n-1}(x)f^n(x)=k=0+k!xki=0k1i!×(ki)!k!2i[i!xi]f^n1(x)

=k=0+xki=0k11(ki)!×2ii![xii!]<mover accent="true">f^</mover>n1(x)=\sum_{k=0}^{+\infty}x^k\sum_{i=0}^{k-1}{1\over (k-i)!}\times{2^i\over i!}[{x^i\over i!}]\hat f_{n-1}(x)=k=0+xki=0k1(ki)!1×i!2i[i!xi]f^n1(x)

=k=0+xki=0k11(ki)![xi]<mover accent="true">f^</mover>n1(2x)=\sum_{k=0}^{+\infty}x^k\sum_{i=0}^{k-1}{1\over (k-i)!}[x^i]\hat f_{n-1}(2x)=k=0+xki=0k1(ki)!1[xi]f^n1(2x)

=i=0+xi[xi]<mover accent="true">f^</mover>n1(2x)k=i+1+xki1(ki)!=\sum_{i=0}^{+\infty}x^i[x^i]\hat f_{n-1}(2x)\sum_{k=i+1}^{+\infty}x^{k-i}{1\over (k-i)!}=i=0+xi[xi]f^n1(2x)k=i+1+xki(ki)!1

=i=0+xi[xi]<mover accent="true">f^</mover>n1(2x)k=1+xkk!=\sum_{i=0}^{+\infty}x^i[x^i]\hat f_{n-1}(2x)\sum_{k=1}^{+\infty}{x^k\over k!}=i=0+xi[xi]f^n1(2x)k=1+k!xk

=(ex1)i=0+xi[xi]<mover accent="true">f^</mover>n1(2x)=(e^x-1)\sum_{i=0}^{+\infty}x^i[x^i]\hat f_{n-1}(2x)=(ex1)i=0+xi[xi]f^n1(2x)

=(ex1)<mover accent="true">f^</mover>n1(2x)=(e^x-1)\hat f_{n-1}(2x)=(ex1)f^n1(2x)

即,<mover accent="true">f^</mover>n(x)=(expx1)<mover accent="true">f^</mover>n1(2x)\hat f_n(x)=(\exp x-1)\hat f_{n-1}(2x)f^n(x)=(expx1)f^n1(2x)

边界 <mover accent="true">f^</mover>0(x)=1\hat f_0(x)=1f^0(x)=1


展开来,我们有

<mover accent="true">f^</mover>n(x)=i=0n1(e2ix1)\hat f_n(x)=\prod_{i=0}^{n-1}(e^{2^ix}-1)f^n(x)=i=0n1(e2ix1)

而我们要求的,就是

ans=i=0k(ki)[xii!]<mover accent="true">f^</mover>n(x)=k!i=0k[xi]<mover accent="true">f^</mover>n(x)(ki)!ans=\sum_{i=0}^{k}\binom ki[{x^i\over i!}]\hat f_n(x)=k!\sum_{i=0}^{k}{[x^i]\hat f_n(x)\over(k-i)!}ans=i=0k(ik)[i!xi]f^n(x)=k!i=0k(ki)![xi]f^n(x)

因此只要能卷出 fn(x)<mtext> </mtext>mod<mtext> </mtext>xk+1f_n(x) \bmod x^{k+1}fn(x)modxk+1 就可得答案。

由展开式,我们有:

<mover accent="true">f^</mover>2n(x)=<mover accent="true">f^</mover>n(x)×<mover accent="true">f^</mover>n(2nx)\hat f_{2n}(x)=\hat f_n(x)\times\hat f_n(2^nx)f^2n(x)=f^n(x)×f^n(2nx)

又有

<mover accent="true">f^</mover>2n+1(x)=<mover accent="true">f^</mover>2n(x)×(e22nx1)\hat f_{2n+1}(x)=\hat f_{2n}(x)\times(e^{2^{2n}x}-1)f^2n+1(x)=f^2n(x)×(e22nx1)

于是可以倍增或者递归卷出 <mover accent="true">f^</mover>n(x)\hat f_n(x)f^n(x)。我采用了后者。

时间复杂度:

T(n)=T(n2)+O(nlogn)=O(nlogn)T(n)=T(\frac n2)+O(n\log n)=O(n\log n)T(n)=T(2n)+O(nlogn)=O(nlogn)


Code

模数 100000000710000000071000000007 太吐了,要 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

总结

开头说了,我没有想到倍增。

这题说明了如何快速卷出出自倍增式的多项式组的指定项

这确实算是一个教训吧。