( 数论专题 )【 斐波那契通项公式 + 等比数列求和公式 】
斐波那契通项公式( 证明略 ):
例题:
求当n趋向于无穷大,Sn等于什么,输出最简分数。
分子是斐波那契数列,分母是K的 i 次方, K是给定的。
思路:
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
int T;cin>>T;
while ( T-- ) {
int k;cin>>k;
int up=k,down=k*k-k-1;
int gcd = __gcd(up,down);
up/=gcd;down/=gcd;
if ( down==1 ) cout << up << endl;
else cout << up << "/" << down << endl;
}
return 0;
}
2020 Multi-University Training Contest 1
Fibonacci Sum
将斐波那契的通项公式带入需要求的式子,再根据二项式定理展开
这样就根据等比公式就可以得到通式,枚举i=0~k相加就是答案。
还有一个问题是a和b不是整数,所以没法在乘法中取模。
这就需要用到二项同余求解
求得x = 383008016, 因为x也可以等于所以在%mod的条件下也可以等于383008016
( 这里提一句,比赛时写二项同余代码太费时间,可以直接暴力求,lst = [ i for i in range(1,mod) if i*i%mod==5 ] , 不到一分钟就能跑出来,类比到其他的情况也可以 )
A = (1+x)*inv(2)%mod B = (1-x)*inv(2)%mod+mod
注意:等比公式可能出现分母为0的情况,显然会出错,需要特判。
注意:需要优化,否则超时。
化简出来的和等于
观察随着 i 的变化tmp的变化,容易发现 i 增加 1 tmp乘以B除以A。
所以就省去了很多个快速幂,直接手动维护tmp的值就可以了。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1000000009;
int a[100005],b[100005];
int qpow( int a, int n )
{
int re = 1;
while ( n ) {
if ( n&1 ) re=(re*a)%mod;
a=(a*a)%mod;
n>>=1;
}
return re;
}
int C( int n, int m )
{
if ( n<m ) return 0;
int ans = ((a[n]*b[m])%mod*b[n-m])%mod;
return ans;
}
int inv( int x )
{
return qpow(x,mod-2);
}
signed main()
{
// cout << qpow(3,128900) << endl;
// cout << qpow(3,128900%mod) << endl;
// x^2 = 5%(1e9+9)
// int x = 383008016;
// cout << (1+x)*inv(2)%mod << endl;
// cout << (1-x)*inv(2)%mod+mod << endl;
int A=691504013,B=308495997;
a[0]=a[1]=1;
for ( int i=2; i<=100003; i++ ) a[i]=(a[i-1]*i)%mod;
for ( int i=0; i<=100003; i++ ) b[i]=qpow(a[i],mod-2);
int n,c,k,T;cin>>T;
while ( T-- ) {
scanf("%lld %lld %lld",&n,&c,&k);
int ac = qpow(A,c);
int bc = qpow(B,c);
int bei = bc*inv(ac)%mod;
int Bei = qpow(bei,n);
int tmp = qpow(ac,k);
int Tmp = qpow(tmp,n);
int sum = 0,now;
for ( int i=0; i<=k; i++ ) {
if ( tmp==1 ) now = C(k,i)*(n%mod)%mod;
else now = C(k,i)*tmp%mod*(Tmp-1)%mod*inv(tmp-1)%mod;
if ( i%2==0 ) sum = (sum+now)%mod;
else {
sum = (sum-now)%mod;
if ( sum<0 ) sum+=mod;
}
tmp = tmp*bei%mod;
Tmp = Tmp*Bei%mod;
}
sum *= inv( qpow(383008016,k) );
sum %= mod;
if ( sum<0 ) sum+=mod;
printf("%lld\n",sum);
}
return 0;
}