1. 程式人生 > 實用技巧 >題解 HDU6755 Fibonacci Sum(二項式定理)

題解 HDU6755 Fibonacci Sum(二項式定理)

題目大意

題目連結

定義斐波那契數列:

\[F_0=0,F_1=1\\ F_n=F_{n-1}+F_{n-2}\ (n>1) \]

給定整數\(N,C,K\)。請計算下式的值:

\[(F_{0})^K+(F_{C})^K+(F_{2C})^K+\dots +(F_{NC})^{K} \]

因為答案太大,請輸出其對\(1000000009\) (\(10^9+9\)) 取模的值。

資料範圍:\(1\leq N,C\leq 10^{18}\)\(1\leq K\leq 10^5\)

本題題解

首先需要了解斐波那契數列的通項公式:

\[F_n=\frac{1}{\sqrt{5}}\left(\left(\frac{1+\sqrt{5}}{2}\right)^{n}-\left(\frac{1-\sqrt{5}}{2}\right)^{n}\right) \]

通過暴力,可以找到\(\bmod10^9+9\)意義下\(\sqrt{5}\)的值是\(383008016\)

const int MOD=1e9+9;
for(int i=0;i<MOD;++i){
	if((long long)i*i%MOD == 5){
		cout<<i<<endl;//383008016
		break;
	}
}

考慮求答案。先把\(\frac{1}{\sqrt{5}}\)提取出來,即:

\[\begin{align} \text{answer}&=\sum_{i=0}^{N}(F_{iC})^{K}\\ &=\sum_{i=0}^{N}\left(\frac{1}{\sqrt{5}}\left(\left(\frac{1+\sqrt{5}}{2}\right)^{iC}-\left(\frac{1-\sqrt{5}}{2}\right)^{iC}\right)\right)^K\\ &=\left(\frac{1}{\sqrt{5}}\right)^K\cdot \sum_{i=0}^{N}\left(\left(\frac{1+\sqrt{5}}{2}\right)^{iC}-\left(\frac{1-\sqrt{5}}{2}\right)^{iC}\right)^{K} \end{align} \]

\(A=\left(\frac{1+\sqrt{5}}{2}\right)^C\), \(B=\left(\frac{1-\sqrt{5}}{2}\right)^C\)。則:

\[\text{answer}=\left(\frac{1}{\sqrt{5}}\right)^K\sum_{i=0}^{N}(A^i-B^i)^K \]

問題轉化為求:

\[\sum_{i=0}^{N}(A^i-B^i)^K \]

把後面的東西用二項式定理展開,得到:

\[=\sum_{i=0}^{N}\sum_{j=0}^{K}{K\choose j}A^{ij}(-B^i)^{K-j} \]

交換和式,得:

\[=\sum_{j=0}^{K}{K\choose j}(-1)^{K-j}\sum_{i=0}^{N}(A^j)^i(B^{K-j})^i \]

後面的\(\sum_{i=0}^{N}(A^j)^i(B^{K-j})^i\),是一個等比數列求和,可以\(O(\log N)\)求出來。(即\(\sum_{i=0}^{n}x^i=\frac{x^{n+1}-1}{x-1}\)\(x\neq 1\))。複雜度裡的\(\log\)來自求\(x^{n+1}\)時使用的快速冪。

於是總時間複雜度就是\(O(K\log N)\)的了。

參考程式碼:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MOD=1e9+9;
const int MAXK=1e5;
int pow_mod(int x,int i){
	int y=1;
	while(i){
		if(i&1)y=(ll)y*x%MOD;
		x=(ll)x*x%MOD;
		i>>=1;
	}
	return y;
}

ll N,C;
int K,fac[MAXK+5],ifac[MAXK+5];
int comb(int n,int k){
	if(n<k)return 0;
	return (ll)fac[n]*ifac[k]%MOD*ifac[n-k]%MOD;
}
int main(){
	ios::sync_with_stdio(0);
	fac[0]=1;
	for(int i=1;i<=MAXK;++i)fac[i]=(ll)fac[i-1]*i%MOD;
	ifac[MAXK]=pow_mod(fac[MAXK],MOD-2);
	for(int i=MAXK-1;i>=0;--i)ifac[i]=(ll)(i+1)*ifac[i+1]%MOD;
	
	
	int T;cin>>T;while(T--){
		cin>>N>>C>>K;
		int A=691504013,B=308495997;
		A=pow_mod(A,C%(MOD-1));
		B=pow_mod(B,C%(MOD-1));
		
		int a=1,b=pow_mod(B,K);
		int ib=pow_mod(B,MOD-2);
		int ans=0;
		for(int j=0;j<=K;++j){
			int x=(ll)a*b%MOD;
			
			if(x==1)
				x=(N+1)%MOD;
			else
				x=(ll)(pow_mod(x,(N+1)%(MOD-1))-1+MOD)%MOD * pow_mod((x-1+MOD)%MOD,MOD-2) % MOD;
			
			if((K-j)&1)
				x=(x==0?x:MOD-x);
			
			ans=((ll)ans+(ll)comb(K,j)*x)%MOD;
			
			a=(ll)a*A%MOD;
			b=(ll)b*ib%MOD;
		}
		
//		for(int i=0;i<=N;++i){
//			ans=(ans+pow_mod((pow_mod(A,i)-pow_mod(B,i)+MOD)%MOD,K))%MOD;
//		}
		
		int mul=276601605;
		mul=pow_mod(mul,K);
		
		ans=(ll)ans*mul%MOD;
		cout<<ans<<endl;
	}
	return 0;
}