java 杭电acm1005_【2020杭电多校round1 1005】HDU6755 Fibonacci Sum(二项式定理)

该博客介绍了如何利用斐波那契数列的通项公式和二项式定理解决杭电ACM1005问题,涉及大数模运算和等比数列求和,给出O(K log N)复杂度的解决方案。
摘要由CSDN通过智能技术生成

题目大意

定义斐波那契数列:

\[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

if((long long)i*i%MOD == 5){

cout<

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

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

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<

}

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值