您的位置:首页 > 其它

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

2020-07-25 19:36 239 查看




思路:首先要知道斐波那契数列的通向公式为
利用这个公式计算会简便很多,可以设D=根号五分之一,A=二分之根号五加一,B=二分之一减根号五,则Fn的K次方可利用二项式定理,得到图中的公式

。发现公式在i取不同值时,有对应的等比数列,求它们的和就行了。注意当公比为1时要特殊判断。
看了这篇文章才理解的,里面也讲了优化的办法https://blog.csdn.net/oampamp1/article/details/107508328
代码仿造题解写得,有微小的改动。

#include <bits/stdc++.h>
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/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: