【2020杭电多校round1 1005】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;
}