[模拟训练]k-斐波那契

题目描述

传送门

【问题描述】

这里写图片描述

【输入】

一行两个整数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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值