1005.Fibonacci Sum(杭州电子科技大学2020学习总结)

1005.Fibonacci Sum(杭州电子科技大学2020学习总结)_第1张图片在这里插入图片描述
在这里插入图片描述
1005.Fibonacci Sum(杭州电子科技大学2020学习总结)_第2张图片
思路:首先要知道斐波那契数列的通向公式为1005.Fibonacci Sum(杭州电子科技大学2020学习总结)_第3张图片
利用这个公式计算会简便很多,可以设D=根号五分之一,A=二分之根号五加一,B=二分之一减根号五,则Fn的K次方可利用二项式定理,得到图中的公式
1005.Fibonacci Sum(杭州电子科技大学2020学习总结)_第4张图片
。发现公式在i取不同值时,有对应的等比数列,求它们的和就行了。注意当公比为1时要特殊判断。
看了这篇文章才理解的,里面也讲了优化的办法https://blog.csdn.net/oampamp1/article/details/107508328
代码仿造题解写得,有微小的改动。

#include 
using namespace std;
typedef long long ll;
const int mod = 1e9+9;//模 
const int AA=691504012;//A的逆元 
const int A=691504013;//二分之一加根号五 
const int B=308495997;//二分之一减根号五 
const int D=276601605;//根号五分之一 
const int NN = 110000;
int f[NN],g[NN],r[NN];
int su[NN];
int j;
//利用斐波那契数列的通向公式和Fnc的规律知道是等比数列求和
//预处理求逆元可以减少时间 
//快速求幂 
inline int modExp(int a,ll n) {
	ll ret=1;
    while(n!=0)
    {
        if (n&1)
            ret=(long long) ret*a%mod;
        a=(long long) a*a%mod;
        n>>=1;
    }
    return ret;
}
//求逆元和阶乘简化运算 
void init() {
	f[0] = g[0] = f[1] = g[1] = r[1] = 1;
	for (int i = 2; i < NN; i++) {
		f[i] = (ll)f[i - 1] * i % mod;//求N的阶乘 
		r[i] = (ll)(mod -  mod / i) * r[mod % i] % mod;
		g[i] = (ll)g[i - 1] * r[i] % mod;
	}
}
//计算排列组合的结果 
inline int nCm(int n, int m) {
	if (m < 0 || m > n) return 0;
	return (ll)f[n] * g[m] % mod * g[n - m] % mod;
}
//计算加所有i取值起来的结果 
inline void add(int &u, int v) {
	u+=v;
	if (u >= mod) u-=mod; 
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	init();
	int tcase;
	
	cin>>tcase;
	for(int i=0;i<tcase;i++){
		ll N,C;
	    int K;
		cin>>N>>C>>K;
		int q1=(ll)modExp(AA, C) * modExp(B, C) % mod;//计算i=1时的公比
		int q=modExp(modExp(A,C),K);//计算i=0时的公比 
		int sum=0;
		int n1 = (N + 1) % mod;
		int n2 = (N + 1) % (mod - 1);
		for(int i=0;i<=K;i++){
		int Cnm=nCm(K,i);
		if(i&1) {
		Cnm=mod-Cnm;
	     }
	     if(q==1){
			add(sum,(ll)Cnm * n1 % mod);//当公比为1 
		}
		  else{
		add(sum,(ll)Cnm * (modExp(q, n2) + mod - 1) % mod * modExp(q-1,mod-2) % mod);
		}
		q = (ll)q * q1 % mod;//变为下一个公比 
	     } 
	    sum=(ll)sum*modExp(D,K) % mod;
      	su[j++]=sum;
    }
    for(int l=0;l<j;l++){//输出 
    	cout<<su[l]<<endl;
	}
	return 0;
}

错误的两个代码:https://paste.ubuntu.com/p/bX2mbzsvpQ/

你可能感兴趣的:(1005.Fibonacci Sum(杭州电子科技大学2020学习总结))