算法导论 30 Problems 答案

30-1

a

本题和题目 4.2-5 类似。

(ax+b)(cx+d)=acx2+(bc+ad)x+bd=acx2+((a+b)(c+d)acbd)x+bd

计算三次乘法 u=(a+b)(c+d),v=ac,w=bd,那么可以计算出多项式的结果为 vx2+(uvw)x+w

b

此处假设 n 是一个偶数。不失一般性,假设现在有两个多项式 A(x)=i=0n1aixi,B(x)=i=0n1bixi,现在计算多项式 C(x)=A(x)B(x) 的系数。假设多项式 A(x),B(x) 的次数 n 都为偶数。

首先考虑第一种分治策略,即分成高阶系数一半和低阶系数一半。

A1(x)=i=0n/21aixi,A2=i=0n/21ai+n/2xi。那么有 A(x)=A2(x)xn/2+A1(x)。类似的,令 B1(x)=i=0n/21bixi,B2=i=0n/21bi+n/2xi。那么有 B(x)=B2(x)xn/2+B1(x)。那么考虑计算如下 3 个多项式的乘积(均是 n/2 次的多项式):

u(x)=(A1(x)+A2(x))(B1(x)+B2(x))v(x)=A2(x)B2(x)w(x)=A1(x)B1(x)

那么最终可以得到 C(x)=v(x)xn+(u(x)v(x)w(x))xn/2+w(x)。可以验证:

C(x)=u(x)xn+(u(x)v(x)w(x))xn/2+w(x)=A2(x)B2(x)xn+A1(x)B2(x)xn/2+A2(x)xn/2B1(x)+A1(x)B1(x)=(A2(x)xn/2+A1(x))(B2(x)xn/2+B1(x))=A(x)B(x)

T(n) 表示这种分治策略的运行时间。首先花费 3T(n/2) 的时间计算出多项式 u(x),v(x),w(x),再花费 Θ(n) 的时间将这三个多项式合成计算结果 C(x)=A(x)B(x),因此可以写出关于 T(n) 的递推式:

T(n)=3T(n/2)+Θ(n)

根据主定理的第 1 个条件,可以得到 T(n)=Θ(nlg3)

接下来考虑第二种分治策略,即按照系数下标的奇偶性划分。

A1(x)=i=0n/21a2ixi,A2=i=0n/21a2i+1xi。那么有 A(x)=A2(x2)x+A1(x2)。类似的,令 B1(x)=i=0n/21b2ixi,B2=i=0n/21b2i+1xi。那么有 B(x)=B2(x2)x+B1(x2)。那么考虑计算如下 3 个多项式的乘积(均是 n/2 次的多项式):

u(x)=(A1(x)+A2(x))(B1(x)+B2(x))v(x)=A2(x)B2(x)w(x)=A1(x)B1(x)

那么最终可以得到 C(x)=v(x2)x2+(u(x2)v(x2)w(x2))x+w(x2)。可以验证:

C(x)=v(x2)x2+(u(x2)v(x2)w(x2))x+w(x2)=A2(x2)B2(x2)x2+A1(x2)B2(x2)x+A2(x2)xB1(x)+A1(x2)B1(x2)=(A2(x2)x+A1(x2))(B2(x2)x+B1(x2))=A(x)B(x)

可见,子问题的数量和规模和第一种分治策略一致,并且可以 Θ(n) 的时间根据分治结果合并出 C(x),因此这种分治策略所需要的时间开销为 Θ(nlg3)

c

先将 n 位二进制数 a,b O(n) 的时间内转化成度数为 n 的多项式 A(x)=i=0n1aixi,B(x)=i=0n1bixi。其中 ak 表示 a 的第 k 比特(bk 同理)。

使用上面的分治算法计算出多项式 C(x)=A(x)B(x),需要花费 O(nlg3),然后花费 O(n) 的时间处理数组 C 的进位,并转化成二进制数 c,最终只需要 O(nlg3) 的时间就可以计算出 c。以下过程是计算出 c 的过程 MULTIPLY-FFTO(nlg3) 中的每个步骤均摊下来,只花费 O(1)(即常数)的比特操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MULTIPLY-FFT(a, b, n)
convert binary numbers a, b into polynomials A, B of degree n
m = 2 ^ (⌈lg n⌉ + 1)
for i = 1 to m - n
INSERT(A, 0)
INSERT(B, 0)
C = FFT-INV(FFT(A, m) ⋅ FFT(B, m), m)
cap = 0
for i = 0 to m - 1
cap = cap + C[i]
C[i] = cap % 2
cap = ⌊cap / 2⌋
convert polynomial C to binary number c
return c

30-2

a

考虑将 ωn2j2k2,ωn3j3k3,,ωndjdkd 都视为是常数。那么有

yk1,k2,,kd=j1=0n11j2=0n21jd=0nd1ak1,k2,,kdωn1j1k1ωn2j2k2ωndjdkd=j2=0n21j3=0n31jd=0nd1j1=0n11ak1,k2,,kdωn1j1k1ωn2j2k2ωndjdkd=j2=0n21j3=0n31jd=0nd1j1=0n11ak1,k2,,kdωn1j1k1ωn2j2k2ωndjdkd=j2=0n21j3=0n31jd=0nd1ωn2j2k2ωndjdkd(j1=0n11ak1,k2,,kdωn1j1k1)=j2=0n21j3=0n31jd=0nd1ωn2j2k2ωndjdkdak1,k2,k3,,kd=j2=0n21j3=0n31jd=0nd1ak1,k2,k3,,kdωn2j2k2ωndjdkd

对于独立的 nn1 个一维 DFT 问题 (k2,k3,,kd),将 k1 视作指数,那么最后一行的计算结果 a:a,k2,k3,,kd=DFTn1(a,k2,k3,,kd),作为下一个问题的步骤的系数 a 的输入,这个过程消去了一个求和符号。在下一次迭代中,仅有 nn1n2 个一维 DFT 问题(下一步是取原来第 2 维),直到所有求和符号都被消去,最终得到的就是多维 DFT 的结果。

b

由于这 d 个求和符号的上下限仅依赖于第 d 维度 nd,因此各个求和符号的位置可以随意改变次序;同样的,所有的 ωnjk 的次序都可以改变。因此,无论哪个维度的消去顺序都是一样的(可以把对应想消去的那一维放到第 1 个位置,然后使用题目 30-2-a 的方法使用 FFT)。因此,原结论成立。

c

假设目前正在消去第 i 维的求和符号,那么一共有 n/j=1inj 个 DFT 问题,这些 DFT 问题的规模大小为 ni,需要花费 O(nilgni) 的时间求解,因此消去第 i 维的求和符号所需要花费的时间为 n/j=1injO(nilgni)=O((n/j=1i1nj)lgni)。因此完成这 d 步循环后,所需要花费的时间为

i=1d((n/j=1i1nj)lgni)nlgni=1d1/(j=1i1ni)nlgni=1d1/(j=1i12)(A)=nlgni=1d21i2nlgn=O(nlgn)

其中步骤 (A) 假定了 ni2,因为如果 ni=1,那么 lgni=0,消去第 i 个求和符号不需要花费任何时间。因此最终原结论成立。

30-3

a

tn1 时,有

A(t)(x)=dtdxtA(x)=dtdxtj=0n1bj(xx0)j=j=0n1dtdxtbj(xx0)j=j=tn1dtdxtbj(xx0)j(A)=j=tn1j!(jt)!bj(xx0)jt=j=0n1t(j+t)!j!bj+t(xx0)j

步骤 (A) 所得是因为所有小于 t 次的多项式进行 t 次求导后的值为 0。因此最终有 A(t)(x0)=btt!

因此对于 t=0,1,2,,n1,维护好 t! 的值,就可以以 O(n) 的时间计算出 A(t)(x0) 的所有值。大概过程由程序 COMPUTE-ATX0 给出:

1
2
3
4
5
6
7
COMPUTE-ATX0(B, n, x)
let D[0 : n - 1] be a new array
fac = 1
for t = 0 to n - 1
D[t] = B[t] * fac
fac = fac * (t + 1)
return D

b

由于我们知道了值 A(x0+ωnk)=j=0n1bjωnj,因此为了求出 bj,只需要对 A(x0+ωnk),k=0,1,,n1 n 个数进行一次逆向 FFT 即可,所需要花费的时间为 O(nlgn)

令示性函数 i(x)=[x0]

c

A(x0+ωnk)=j=0n1aj(x0+ωnk)j=j=0n1ajr=0j(jr)ωnkrx0jr=j=0n1ajr=0jj!r!(jr)!ωnkrx0jr=j=0n1ajr=0jj!r!(jr)!ωnkrx0jr=j=0n1ajr=0jj!r!ωnkrx0jr(jr)!=j=0n1aj(r=0jj!r!ωnkrx0jr(jr)!+r=j+1n1j!r!ωnkr0)=j=0n1aj(r=0jj!r!ωnkrg(rj)+r=j+1n1j!r!ωnkrg(rj))=j=0n1aj(r=0n1j!r!ωnkrg(rj))=r=0n1j=0n1ajj!r!ωnkrg(rj)=r=0n1j=0n1f(j)r!ωnkrg(rj)=r=0n1[ωnkrr!j=0n1f(j)g(rj)]

因此最终原结论成立。

d

h(j)=g(j(n1)),那么有 A(x0+ωnk)=r=0n1[ωnkrr!j=0n1f(j)h(n+r1j)],然而对于 jn,都有 h(j)=0

jn 时,假设 f(j)=0,令 yr=j=0n1f(j)h(n+r1j)=j=0n+r1f(j)h(n+r1j),那么可以在 O(nlgn) 的时间内通过多项式卷积计算出 yr,其中 r[0,n)

zr=yrr!,那么得到 A(x0+ωnk)=r=0n1zrωnkr。接下来再使用一次 FFT 即可计算出 A(x0+ωnk),其中 k[0,n)

然后,按照题目 30-3-b 的结论,使用一次逆向 FFT,得到多项式 A 的系数 b0,b1,,bn1

最后使用题目 30-3-a 的结论,通过系数 b O(n) 的时间内计算出 A(x) 所有非平凡导数在 x0 的值。由于整个过程仅仅使用了 5 次 FFT,以及最后一步以 O(n) 的时间计算出所有答案,因此整个过程的时间复杂度为 O(nlgn)

整个大致过程由 COMPUTE-DERIVATIVE-BY-FFT 给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
COMPUTE-DERIVATIVE-BY-FFT(A, n, x)
m = 2 ^ (⌈lg n⌉ + 1)
for i = 1 to m - n
INSERT(A, 0)
let F[0 : m - 1], H[0 : m - 1] ,fac[0, m - 1] be new arrays
fac[0] = 1
for i = 1 to n - 1
fac[i] = fac[i - 1] * i
for i = 0 to n - 1
F[i] = A[i] * fac[i]
l = i - (n - 1)
H[i] = exp(x, -l) / fac[-l]
Y = FFT-INV(FFT(F, m) ⋅ FFT(H, m), m)
let Z[0 : m - 1], D[0 : n - 1] be new arrays
for i = 0 to n - 1
Z[i] = Y[i + m / 2] / fac[i]
B = FFT-INV(Z, m)
for i = 0 to n - 1
D[i] = B[i] * fac[i]
return 0

30-4

a

这个问题等价于证明:xzA(x)A(z)

首先证明一个引理:n1,其中 n 是一个整数,都有 abanbn。接下来使用归纳法进行证明。当 n=1 时,明显成立。当 n>1 时,假设对于 k=1,2,,n1,都有 abakbk。考虑 anbn,那么有 anbn=(ab)an1+b(an1bn1)。由于前者包含一个因子 (ab),因此 ab 整除 (ab)an1;按照假设,可知 abb(an1bn1),因此得出 abanbn,该引理成立。

接下来证明原结论。考虑 A(x)A(z),那么有 A(x)A(z)=i=0n1ai(xizi)。当 i=0 时,这个项为 0;对于 i>0,按照上面的引理,都有 xzxizi,因此最终有 xzA(x)A(z)。即

A(x)mod(xz)=A(z)

b

可以得知 Qkk(x)=A(x)mod(xxk),因此按照题目 30-4-a 的结论,有 Qkk(x)=A(xk)

由于多项式 P0,n1(x) 的次数为 n,但是 A(x) 的次数为 n1,因此 A(x)modP0,n1(x)=A(x),即 Q0,n1(x)=A(x)

c

本题考虑证明一个更强的结论:对于任意非空集合 S{0,1,,n1} 的任意一个非空子集 T,都有 A(x)modiT(xxi)=(A(x)modiS(xxi))modiT(xxi)

s(x)=iS(xxi),t(x)=iT(xxi),可见 t(x)s(x)。接下里是证明:构造两个多项式 q1(x),r1(x1) 满足 A(x)=q1(x)s(x)+r1(x),其中 degree(r1)<|S|,那么有 A(x)mods(x)=r1(x)。同时构造两个多项式 q2(x),r2(x) 满足 r1(x)=q2(x)t(x)+r2(x),其中 degree(r2)<|T|。由于 t(x)s(x),令多项式 u(x)=s(x)/t(x),那么有

A(x)=q1(x)s(x)+r1(x)=q1(x)u(x)t(x)+q2(x)t(x)+r2(x)=(q1(x)u(x)+q2(x))t(x)+r2(x)

由于 degree(r2)<|T|,因此有 A(x)modt(x)=r2(x),上面证明的结论成立。

假设现在 S={i,i+1,,j}。当 T={i,i+1,,k} 时,则相当于证明了 A(x)modPik(x)=(A(x)modPij(x))modPik(x),即 Qik(x)=Qij(x)modPik(x)。当 T={k,k+1,,j} 时,则相当于证明了 A(x)modPkj(x)=(A(x)modPij(x))modPkj(x),即 Qkj(x)=Qij(x)modPkj(x),因此原结论成立。

d

m=2lgn。整个过程分为两个阶段。按照题目 30.2-7 的思路,首先自底向上,使用 FFT 计算出所有的 Plr:k:rl+1=2k,2kl,这个阶段将花费 O(mlg2m) 的时间。接下来则是自顶向下计算出所有的 Qlr:k:rl+1=2k,2kl,同样的,在第 k 轮迭代中计算单次多项式的长度为 m2k1,取模所需要花费的时间为 O(m2k1lgm2k1)。一共需要进行 2k12 次,因此总共所需要花费的时间为 O(mlgm)。因此第二个阶段也将花费 O(mlg2m) 的时间。

由于两个阶段都使用了 O(mlg2m) 的运行时间,并且 n=Θ(m),因此这个算法的时间复杂度为 O(nlg2n),具体过程由 EVALUATE-N-VALUES 给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 假设函数PLOY-MULTIPLY和POLY-MODULO会将多项式的长度拓展成2的幂,并且用FFT和FFT-INV分别作为子程序运行,以O(n lg n)的时间进行,这里忽略了实现细节。
EVALUATE-N-VALUES(A, X, n)
m = 2 ^ (⌈lg n⌉)
c = ⌈lg n⌉
for i = 0 to m
if i < n
P_{ii} = [-X[i], 1]
else
P_{ii} = [1, 0]
for k = 1 to c
for l = 0 to m by 2^k
r = l + 2 ^ k - 1
P_{l, r} = PLOY-MULTIPLY(P_{l, l + 2 ^ (k - 1) - 1}, P_{l + 2 ^ (k - 1), r})
Q_{0, m - 1} = A
for k = c to 1
for l = 0 to m by 2^k
r = l + 2 ^ k - 1
Q_{l, l + 2 ^ (k - 1) - 1} = PLOY-MODULO(Q_{l, r}, P_{l + 2 ^ (k - 1), r})
Q_{l + 2 ^ (k - 1), r} = PLOY-MODULO(Q_{l, r}, P_{l, l + 2 ^ (k - 1) - 1})
let Y[0 : n - 1] be a new array
for i = 0 to n - 1
Y[i] = Q_{ii}
return Y

30-5

事实上,这种在 Zp 上的傅里叶变换称为数论变换

a

按照素数定理,从 1 m 中素数的个数占比约为 1lnm。因此从 1 nlnn 中选取到一个质数的概率约为 1lnn+lnlnn1lnn。考虑从 k=1,2,3,,lnn,考察存在 k 使得 kn+1 是一个质数的概率 p。可以计算得到

p1(11lnn+lnlnn)lnn1(11lnn)lnn>11e0.632121

因此,有相当高的概率使得这 lnn 数中存在一个质数,因此需要检查的 k 期望个数为 O(lgn)。因此 p 的期望值为 O(nlgn),并且 p 的长度值的期望是 O(lg(nlgn))=O(lgn+lglgn)=O(lgn)

b

由于 g Zp 生成元,因此 g Zp 上的阶 λp(g)=p1=kn。由于 w=gkmodp,因此 λp(w)=n。也就是说,Zp 上的一个循环子群 w 的大小为 n。按照 ωn 的定义,有 ωnn=1,类似的,按照费马小定理,有 wn(gk)ngp11(modp)

接下来证明引理 / 定理 / 推论 30.3,30.4,30.5,30.6, 30.76 在 w 中是成立的。

引理 30.3 的证明:考虑 n 的某个因子 d,令 w=wd,那么有 wk/d(wd)k/dwk(modp),因此原结论成立。

推论 30.4 的证明:不难知道 wn/2gkn/21(modp),(由于 gkn1(modp),因此 gkn/2modp 的值要么为 1,要么为 1,但是它的值必定是 1,因为 g 是原根)。

引理 30.5 的证明:(wk+n/2)2w2k+nw2kwn(wk)2(modp),因此结论得证。

引理 30.6 的证明:当 nk 时,有 wk1(modp) 成立。证明过程和原本的定理 30.6 的计算过程一致,原结论得证。

定理 30.7 的证明:此时 Vn1 的第 j 行第 k 列的项为 wjkn1modp。由于 p 是奇数,且 n<p,因此 gcd(n,p)=1,因此在 Zp 中存在 n 的逆元 n1,结论中的写法是成立的,考虑 [Vn1Vn]kk 的值,有 [Vn1Vn]kkj=0n1(wjkn1)(wjk)n1j=0n1wj(kk)(modp)。其余证明过程类似,因此原结论成立。

那么在 Zp 上的 DFT 问题定义为:给定长度为 n 的序列 (a0,a1,,an1),计算 yj=i=0n1ai(wj)imodp,其中 w=gk。最终,计算结果 yjZp,可见计算结果是封闭的。正向 DFT 的过程成立。

现在在 Zp 上的逆向 DFT 问题定义为:给定长度为 n 的序列 (y0,y1,,yn1),构造一组序列 (a0,a1,,an1)Zpn,使得 j[0,n),yj=i=0n1ai(wj)imodp 均成立,其中 w=gk。那么按照类似的结论,由于 gcd(w,p)=1,因此 w Zp 中也存在逆元 w1。容易验证 w=w1,因此 ak=n1i=0n1yi(ωk)imodp 的整个计算过程是封闭的,即 DFT 的逆过程是正确定义的。

c

FFTFFT-INV 改造后,可以得到 FFT-OVER-RINGFFT-INV-OVER-RING 算法,程序如下给出。由于操作分别和 FFTFFT-INV 一致,因此其时间复杂度均为 O(nlgn)。需要注意的是,w1 n1 可以提前计算好,避免以后的重复计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
FFT-OVER-RING(a, n, p, wn)
if n == 1
return a
w = 1
a-even = (a_0, a_2, ..., a_{n - 2})
a-odd = (a_1, a_3, ..., a_{n - 1})
y-even = FFT-INV(FFT-OVER-RING, n / 2, p, wn * wn % p)
y-odd = FFT-INV(FFT-OVER-RING, n / 2, wn * wn % p)
for k = 0 to n / 2 - 1
y_k = (a-even_{k} + w * a-odd_{k}) % p
y_{k + n / 2} = (a-even_{k} - w * a-odd_{k}) % p
w = w * wn % p
return y

// wn^{-1}和n^{-1}需要提前使用扩展欧几里得算法计算好,避免重复计算,结果分别用wn-inv和n-inv表示。
FFT-INV-OVER-RING(y, n, p, wn-inv)
if n == 1
return a
w = 1
y-even = (y_0, y_2, ..., y_{n - 2})
y-odd = (y_1, y_3, ..., y_{n - 1})
a-even = FFT-INV-OVER-RING(y-even, n / 2, p, wn-inv * wn-inv % p)
a-odd = FFT-INV-OVER-RING(y-odd, n / 2, p, wn-inv * wn-inv % p)
for k = 0 to n / 2 - 1
a_k = (a-even_{k} + w * a-odd_{k}) * n-inv % p
a_{k + n / 2} = (a-even_{k} - w * a-odd_{k}) * n-inv % p
w = w * wn-inv % p
return a

d

由于 n=8,因此 gn=gp1n=9

那么 k[0,n),都有 yk=i=0n1ai(gnk)imodp。可以计算得到

y0=i=0n1ai(gn0)imodp=14y1=i=0n1ai(gn1)imodp=10y2=i=0n1ai(gn2)imodp=10y3=i=0n1ai(gn3)imodp=4y4=i=0n1ai(gn4)imodp=8y5=i=0n1ai(gn5)imodp=11y6=i=0n1ai(gn6)imodp=13y7=i=0n1ai(gn7)imodp=15

因此 DFT 的结果为 (14,10,10,4,8,11,13,15)