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\)的式子,然后进行分类讨论:

  1. 当i&1=0:\(F_n=(-1)^{k\times \frac{i}{2}}F_j\)
  2. 当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;
}

总结

这个考的东西真的很奇怪,也算是我的积累问题吧,毕竟斐波那契我就只知道那两个通项公式,还是得多做点题

posted @ 2023-05-07 20:39  6penny  阅读(54)  评论(0编辑  收藏  举报