51nod 1365 Fib(N) mod Fib(K)-题解
51nod 1365 Fib(N) mod Fib(K)
个人评价:考一些奇奇怪怪的知识点呢
算法
矩阵快速幂、斐波那契公式
题面
求\(F_n\%F_k\)的值,\(1\leq n,k\leq 1e18\)
问题分析
我一开始居然想着直接矩阵快速幂求出两个值算,我也是真的牛……
我们要知道这些斐波那契公式(考的真怪)
\[F_{-n}=(-1)^{n-1}F_n
\]
\[F_n=F_kF_{n-k+1}+F_{k-1}F_{n-k}
\]
\[F_{k-1}^2+F_{k-1}F_k-F_k^2=(-1)^k
\]
问题求的是\(F_n \% F_k\)的值,所以我们考虑所有计算推导相等在模\(F_k\)下进行
开始娱乐地推式子了
\[\begin{aligned}
F_n&=F_kF_{n-k+1}+F_{k-1}F_{n-k} \\
&=F_{k-1}F_{n-k}\\
&=F_{k-1}(F_kF_{n-2k+1}+F_{k-1}F_{n-2k})\\
&=F_{k-1}^2F_{n-2k}\\
\end{aligned}
\]
所以可以得到\(F_n=F_{k-1}^{\lfloor\frac{n}{k}\rfloor}F_{n\%k}\)
看到最后一个公式,我们也在模\(F_k\)意义下推导
\[\begin{aligned}
(-1)^k&=F_{k-1}^2+F_{k-1}F_k-F_k^2 \\
&=F_{k-1}^2\\
\end{aligned}
\]
令\(\lfloor\frac{n}{k}\rfloor=i,n\%k=j\) 考虑将这个带入到\(F_n\)的式子,然后进行分类讨论:
- 当i&1=0:\(F_n=(-1)^{k\times \frac{i}{2}}F_j\)
- 当i&1=1:\(F_n=F_{k-1}^iF_j=F_{k-1}^i(F_{k-1}F_{j-k}+F_kF_{j-k+1})=F_{k-1}^{i+1}F_{j-k}=(-1)^{\frac{i+1}{2}k+k-j-1}F_{k-j}\)
代码实现
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll p=1e9+7;
struct Matrix{
ll x[3][3];
};
int check(int x,int y,int z=0){
if((x&1)&&(y&1))return z&1?1:-1;
return z&1?-1:1;
}
Matrix mul(Matrix a,Matrix b){
Matrix res;
memset(res.x,0,sizeof res.x);
for(ll i=1;i<=2;i++){
for(ll j=1;j<=2;j++){
for(ll k=1;k<=2;k++){
res.x[i][j]=(res.x[i][j]+a.x[i][k]*b.x[k][j]%p)%p;
}
}
}
return res;
}
ll qpow(Matrix a,ll k){
Matrix res;
memset(res.x,0,sizeof res.x);
for(ll i=1;i<=2;i++)res.x[i][i]=1;
while(k){
if(k&1)res=mul(res,a);
a=mul(a,a);
k>>=1;
}
return res.x[1][2]%p;
}
void solve(){
ll n,k;
Matrix a;
memset(a.x,0,sizeof a.x);
a.x[1][1]=a.x[1][2]=a.x[2][1]=1;
scanf("%lld%lld",&n,&k);
ll i=n/k,j=n%k;
ll ans=0,mod=qpow(a,k);
if(i%2==0){
if(j==k)ans=0;
else ans=qpow(a,j);
ans=ans*check(i/2,k);
if(ans<0)ans=(ans+mod)%p;
ans=(ans+p)%p;
}else{
if(j==0)ans=0;
else ans=qpow(a,k-j);
ans=ans*check((i+1)/2,k,k-j-1);
if(ans<0)ans=(ans+mod)%p;
ans=(ans+p)%p;
}
printf("%lld\n",(ans+p)%p);
}
int main(){
ll T;
scanf("%lld",&T);
while(T--)solve();
return 0;
}
总结
这个考的东西真的很奇怪,也算是我的积累问题吧,毕竟斐波那契我就只知道那两个通项公式,还是得多做点题