1 条题解

  • 0
    @ 2022-4-16 9:12:24

    Update

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

    前言

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

    所以,这算一个教训吧


    思路

    以下默认 b0=0b_0=0

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

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

    由定义,我们有

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

    我们发现一个 dp 式:

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

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

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

    然后,设 EGF\operatorname{EGF}

    $$\hat f_n(x)=\sum_{k=0}^{+\infty}f_{n,k}{x^k\over k!} $$

    那么:

    $$\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) $$$$=\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) $$$$=\sum_{k=0}^{+\infty}x^k\sum_{i=0}^{k-1}{1\over (k-i)!}[x^i]\hat f_{n-1}(2x) $$$$=\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)!} $$$$=\sum_{i=0}^{+\infty}x^i[x^i]\hat f_{n-1}(2x)\sum_{k=1}^{+\infty}{x^k\over k!} $$$$=(e^x-1)\sum_{i=0}^{+\infty}x^i[x^i]\hat f_{n-1}(2x) $$=(ex1)f^n1(2x)=(e^x-1)\hat f_{n-1}(2x)

    即,f^n(x)=(expx1)f^n1(2x)\hat f_n(x)=(\exp x-1)\hat f_{n-1}(2x)

    边界 f^0(x)=1\hat f_0(x)=1


    展开来,我们有

    f^n(x)=i=0n1(e2ix1)\hat f_n(x)=\prod_{i=0}^{n-1}(e^{2^ix}-1)

    而我们要求的,就是

    $$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)!} $$

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

    由展开式,我们有:

    f^2n(x)=f^n(x)×f^n(2nx)\hat f_{2n}(x)=\hat f_n(x)\times\hat f_n(2^nx)

    又有

    $$\hat f_{2n+1}(x)=\hat f_{2n}(x)\times(e^{2^{2n}x}-1) $$

    于是可以倍增或者递归卷出 f^n(x)\hat f_n(x)。我采用了后者。

    时间复杂度:

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

    Code

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

    总结

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

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

    这确实算是一个教训吧。

    • 1

    信息

    ID
    4435
    时间
    7000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    2
    上传者