9964. Fibonacci vs Polynomial
Problem code: PIBO
Define a sequence Pib(n) as following
- Pib(0) = 1
- Pib(1) = 1
- otherwise, Pib(n) = Pib(n-1) + Pib(n-2) + P(n)
Here P is a polynomial.
Given n and P, find Pib(n) modulo 1,111,111,111.
Input
First line of input contains two integer n and d (0 ≤ n ≤ 109, 0 ≤ d ≤ 100), d is the degree of polynomial.
The second line contains d+1 integers c0,c1 … cd, represent the coefficient of the polynomial(Thus P(x) can be written as Σcixi). 0 ≤ ci ≤ 100 and cd ≠ 0 unless d = 0.
Output
A single integer represents the answer.
Example
<b>Input:</b> 10 0 0 <b>Output:</b> 89 <b>Input:</b> 10 0 1 <b>Output:</b> 177 <b>Input:</b> 100 1 1 1 <b>Output:</b> 343742333
题解
(第一次用latex详细写计算过程,调试了一下午的数学公式):
我们都知道可以这么快速计算斐波那契数列:令 F=(1110), 那么 Fn(Fib(n)Fib(n−1))=(Fib(n+1)Fib(n)) . 我们也知道二项式公式:(n+1)k=k∑i=0Cikni,
(n+1)d=C0dnd+C1dnd–1+⋯+Cddn0,
(n+1)d–1=C0d–1nd–1+C1d–1nd–2+⋯+Cd–1d–1n0,
⋯.
令 A=(11cdcd−1⋯c0100⋯⋯000CddCd−1d⋯C0d000Cd−1d−1⋯C0d−1⋮⋮⋯⋯⋱⋮0000⋯C00),pn=(Pibo(n)Pibo(n−1)ndnd−1⋮n0)
那么:
Apn=pn+1
也就是:
(11cdcd−1cdotsc0100cdotscdots000CddCd−1d⋯C0d000Cd−1d−1⋯C0d−1⋮⋮⋯⋯⋱⋮0000⋯C00)(Pibo(n−1)Pibo(n−2)ndnd−1⋮n0)=(Pibo(n)Pibo(n−1)(n+1)d(n+1)d−1⋮(n+1)0)
复杂度是:O((d+3)3logn) 也就是1033log109
进行优化:
令B(n)=Pibo(n)+d∑i=0kini=Pibo(n)+kdnd+kd−1nk−1+⋯+k0,那么
B(n)=B(n−1)+B(n−2)
也就有(B(n)B(n−1))=(1110)n−1(B(1)B(0))
现在复杂度是O(8logn) to calculate Bn,8log109
但是我们需要知道k0⋯kd 来计算初始值B(1)),(B(0) 以及从B(n)反解出 Pibo(n)。
从B(n)=B(n−1)+B(n−2) 我们可以得到:
Pibo(n)+d∑i=0kini=[Pibo(n−1)+d∑i=0ki(n−1)i]+[Pibo(n−2)+d∑i=0ki(n−2)i]
和原来的比较:
Pibo(n)=Pibo(n−1)+Pibo(n−2)+d∑i=0cini
可以得出
d∑i=0ki(n−1)i+d∑i=0ki(n−2)i−d∑i=0kini≡d∑i=0cini
也就是
d∑i=0[ki(n−1)i+ki(n−2)i−kini]≡d∑i=0cini
化简这个式子得到:
(C00C11[(−1)1+(−2)1]C22[(−1)2+(−2)2]⋯Cdd[(−1)d+(−2)d]0C01C12[(−1)1+(−2)1]⋯Cd−1d[(−1)d−1+(−2)d−1]00C02⋯Cd−2d[(−1)d−2+(−2)d−2]⋯⋯⋮⋱⋮000⋯C0d)(k0k1k2⋮kd)=(c0c1c2⋮cd)
可以容易发现这是一个上三角且主对角线是1的矩阵,利用下面的式子可以进一步化简,而且不需要进行计算Ckn时候的阶乘计算,而全部化成加法运算,进一步优化
Ckn=Ck−1n−1+Ckn−1
python代码
如下:
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | # -*- coding: utf-8 -*- """ Created on Thu Feb 06 16:56:53 2014 @author: rexdf """ """ 1 2014-02-06 11:39:02 rexdf accepted 0.06 4.0M PYTH 2.7 """ modulo = 1111111111 #It's not a prime number!!! def matrix2_2Mul(A,B): return [[(A[ 0 ][ 0 ] * B[ 0 ][ 0 ] + A[ 0 ][ 1 ] * B[ 1 ][ 0 ]) % modulo,(A[ 0 ][ 0 ] * B[ 0 ][ 1 ] + A[ 0 ][ 1 ] * B[ 1 ][ 1 ]) % modulo],[(A[ 1 ][ 0 ] * B[ 0 ][ 0 ] + A[ 1 ][ 1 ] * B[ 1 ][ 0 ]) % modulo,(A[ 1 ][ 0 ] * B[ 0 ][ 1 ] + A[ 1 ][ 1 ] * B[ 1 ][ 1 ]) % modulo]] def matrix2_2Pow(A,n): ret = [[ 1 , 0 ],[ 0 , 1 ]] while n: if n& 1 : ret = matrix2_2Mul(ret,A) A = matrix2_2Mul(A,A) n>> = 1 return ret def main(): n,d = map ( int , raw_input ().split()) dat = map ( int , raw_input ().split()) if n< 2 : print 1 else : comb = [[ 0 ] * (d + 1 ) for i in range ( 0 ,d + 1 )] for i in range ( 0 ,d + 1 ): comb[ 0 ][i] = comb[i][i] = 1 for i in range ( 1 ,d): for j in range (i + 1 ,d + 1 ): comb[i][j] = comb[i][j - 1 ] + comb[i - 1 ][j - 1 ] if comb[i][j]>modulo:comb[i][j] - = modulo fn1 = [ 0 ] * (d + 1 ) fn1[ 0 ] = 1 for i in range ( 1 ,d + 1 ): fn1[i] = fn1[i - 1 ] * ( - 1 ) fn2 = [ 0 ] * (d + 1 ) fn2[ 0 ] = 0 if d: fn2[ 1 ] = - 2 for i in range ( 2 ,d + 1 ): fn2[i] = (fn2[i - 1 ] * ( - 2 )) % modulo alf = [ 0 ] * (d + 1 ) alf[d] = dat[d] #print "alf_d = ",alf[d],dat[d] for i in range (d - 1 , - 1 , - 1 ): tmp = dat[i] for j in range (d,i, - 1 ): tmp - = comb[i][j] * (fn1[j - i] + fn2[j - i]) * alf[j] #tmp/=calc_dat[i][i] alf[i] = tmp % modulo #for i in range(0,d+1):print i,alf[i] B = [[ 1 + sum (alf) % modulo],[ 1 + alf[ 0 ] % modulo]] #print B[0],B[1] A = [[ 1 , 1 ],[ 1 , 0 ]] C = matrix2_2Pow(A,n - 1 ) #Bn=matrixMul2(C,B) Bn = (C[ 0 ][ 0 ] * B[ 0 ][ 0 ] + C[ 0 ][ 1 ] * B[ 1 ][ 0 ]) % modulo ans = 0 pown = 1 for i in range ( 0 ,d + 1 ): ans + = pown * alf[i] ans % = modulo pown * = n pown % = modulo ans = Bn - ans ans % = modulo if ans< 0 : ans + = modulo print ans if __name__ = = '__main__' : main() |