*Fibonacci Sum-2020杭電多校1
題意:
分析:
一開始想的是用矩陣來求,但發現樣例一直過不去。最後才發現,\((AB)^k \ne A^kB^k\),其中 \(A,B\) 為矩陣,做了怎麼久才發現是一個假演算法。
看來題解才發現用的是斐波那契數列的通項公式:
\[F_n=\frac{1}{\sqrt{5}}[(\frac{1+\sqrt{5}}{2})^n-(\frac{1-\sqrt{5}}{2})^n] \]
同時還要知道:\(5\) 是 \(1e9+9\) 的二次剩餘
且有:
\[383008016^2 \equiv 616991993^2 \equiv 5\ (mod\ 1e9+9) \]
由此可知,在模 \(1e9+9\)
可以求出 \(\sqrt{5}\) 的逆元為 \(invsqrt5=276601605\)。
令 \(a=\frac{1+\sqrt{5}}{2},b=\frac{1-\sqrt{5}}{2}\),通過快速冪可以求得:\(a=691504013,b=308495997\)。
所以,有:
\[F_{n}^{k}=invsqrt5^k*[a^n-b^n]^k \]
而根據二項式展開,有:
\[(a^n-b^n)^k=C(k,0)*(a^n)^0*(b^n)^k+C(k,1)*(a^n)^{1}*(b^n)^{k-1}+...+C(k,k)*(a^n)^k*(b^n)^0 \]
所以,
\[ans=invsqrt5*\sum_{i=1}^{k}{[C(k,i)\sum_{j=1}^{n}{(a^{jc})^i(-b^{jc})^{k-i}}]} \]
又根據等比數列的求和公式:
\[S_n=\sum_{j=1}^{n}{(a^{jc})^i(-b^{jc})^{k-i}}=\frac{1-(a^{cin}*b^{c(k-i)n})}{1-a^{ci}*b^{c(k-i)}}*a^{ci}*(-1)^{k-i}*b^{c(k-i)} \]
注意特判公比為 \(1\) 的情況,其中\(a^{cin},b^{c(k-i)n},a^{jc},b^{jc}\) 均可以預處理出來。
最終的答案為:
\[ans=invsqrt5*\sum_{i=1}^{k}{S_i} \]
複雜度為:\(O(klogn)\),能預處理的都預處理,否則任意超時。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int mod=1e9+9;
const int phi=1e9+8;
ll C[N],fac[N],inv[N],sa[N],sb[N];
ll inv2=500000005,p=383008016,q=276601605;
ll power(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void init()//預處理出階乘和階乘逆元
{
int maxn=1e5;
fac[0]=1;
for(int i=1;i<=maxn;i++)
fac[i]=fac[i-1]*i%mod;
inv[maxn]=power(fac[maxn],mod-2);
for(int i=maxn-1;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
}
void getC(ll k)
{
for(int i=0;i<=k;i++)
C[i]=fac[k]*inv[i]%mod*inv[k-i]%mod;
}
int main()
{
int t;
init();
scanf("%d",&t);
//fn=q*(x^n-y^n)
ll x=(1+p)*inv2%mod;
ll y=(1-p+mod)*inv2%mod;
while(t--)
{
ll n,c,k,ans=0;
scanf("%lld%lld%lld",&n,&c,&k);
getC(k);//預處理組合數
ll tx=power(x,c);
ll ty=power(y,c);
ll invty=power(ty,mod-2);
sa[0]=power(ty,k);
for(int i=1;i<=k;i++)
sa[i]=sa[i-1]*tx%mod*invty%mod;
tx=power(tx,n);
ty=power(ty,n);
invty=power(ty,mod-2);
sb[0]=power(ty,k);
for(int i=1;i<=k;i++)
sb[i]=sb[i-1]*tx%mod*invty%mod;
int f=((k%2)?1:-1);
for(int i=0;i<=k;i++)
{
f=-f;
if(sa[i]==1)
{
ll tmp=C[i]*f*(n%mod)%mod;
ans=(ans+tmp+mod)%mod;
continue;
}
ll up=(1-sb[i]+mod)%mod;
ll down=(1-sa[i]+mod)%mod;
down=power(down,mod-2);
ll tmp=up*down%mod;
tmp=(tmp*sa[i]%mod*f+mod)%mod;
tmp=tmp*C[i]%mod;
ans=(ans+tmp)%mod;
}
ans=ans*power(q,k)%mod;
printf("%lld\n",ans);
}
return 0;
}