题目描述
【问题描述】
【输入】
一行两个整数n P
【输出】
从小到大输出可能的k,若不存在,输出None
【样例输入1】
5 5
【样例输出】
2
【样例解释】
f[0] = 2
f[1] = 2
f[2] = 4
f[3] = 6 mod 5 = 1
f[4] = 5 mod 5 = 0
f[5] = 1
30%的数据保证n, P ≤1000
100%的数据保证n, P ≤10^9
*分析
观察递推式及数据范围,只能用矩阵快速幂。又k_f[0]=k_f[1]=k,所以k_f[n]=f[n+1]*k;
题目要求的是k_f[n]%p==1的值,相当于k_f[n]模p同余1,这时自然想到拓欧。
notice:
1、此题看似要输出所有可能的解,但由于gcd(k_f[n],p)==1,因而只有唯一解,若二者不互质,则无解。
2、此K_斐波拉契数列从0开始标号。
3、这里最大1e9*1e9 要用long long
此题也可用逆元求解
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
ll n,p;
struct jz{
ll w[5][5],xl,yl;
jz(){ memset(w,0,sizeof(w));}
};
jz operator *(jz a,jz b){
jz ans;
memset(ans.w,0,sizeof(ans.w));
for(ll i=1;i<=2;i++)
for(ll j=1;j<=2;j++)
for(ll k=1;k<=2;k++)
ans.w[i][j]=(ans.w[i][j]+a.w[i][k]*b.w[k][j]%p)%p;
return ans;
}
jz x,t,an;
jz jzpow(jz a,ll b){
jz ans;
ans.w[1][1]=1;ans.w[1][2]=0;
ans.w[2][1]=0;ans.w[2][2]=1;
while(b){
if(b&1) ans=ans*a;
a=a*a;
b=b>>1;
}
return ans;
}
inline bool exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){x=1;y=0;return a!=1;}
if(exgcd(b,a%b,y,x)) return true;
y-=a/b*x;
return false;
}
int main(){
scanf("%lld%lld",&n,&p);//p为mod
x.w[1][1]=1;x.w[2][1]=1;
x.w[1][2]=1;x.w[2][2]=0;
t.w[1][1]=1;t.w[2][1]=1;
t.w[1][2]=0;t.w[2][2]=0;
memset(an.w,0,sizeof(an.w));
an=jzpow(x,n-1)*t;
ll x,y,fn=an.w[1][1]%p;
if(exgcd(fn,p,x,y)) printf("None\n");
else printf("%lld\n",(x%p+p)%p);
return 0;
}