【NOIP 校内模拟】k-斐波拉契(矩阵快速幂+乘法逆元)

【NOIP 校内模拟】k-斐波拉契(矩阵快速幂+乘法逆元)

这道题真的很好啊!刚好把这几天学的东西结合在了一起

首先我们可以发现,一个k-斐波拉契数列的每一项就是普通的斐波拉契数列的倍数

因此问题转变成了k * f[n] =1 (mod p) 求k

卧槽?这不就是求f[n]在mod p意义下的乘法逆元吗??

卧槽?f[n]可以用矩阵快速幂跑出??右转洛谷P1962

卧槽??变一下形 kf[n]+yp=1 不就是一个扩欧吗???

卧槽???根据定理当gcd(f[n],p)=1的时候原方程才有解,也就是说如果不等于1的话就输出“None”

卧槽???????由于f[n]在mod p意义下 在[0,p)内的乘法逆元只有一个 那所以只有一个解???????

多提一句 拓展欧几里得算法计算逆元 常常会搞出负数 但是由于逆元之间的间距刚好就是模数p 所以只需要在最后一句话添上(x%p+p)%p即可(因为c++负数取模与数学规定不一样)
代码仅供参考 不保证能否AC(我tm没地方交啊啊啊啊啊啊)

#include<iostream>
#define ll long long
using namespace std;
struct matrix
{
    ll m[105][105];
};
ll n=2,p,k;
matrix base;
matrix mul(matrix A,matrix B)
{
    matrix C;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            C.m[i][j]=0;
        } 
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=1;k<=n;k++)
            {
                C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j])%p;
            }
        }
    }
    return C;
}
matrix quickpow(matrix A,ll y)
{
    matrix ans;
    //构造单位矩阵 
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)    ans.m[i][j]=1;
            else ans.m[i][j]=0;
        }
    }
    while(y)
    {
        if(y&1) ans=mul(ans,A);
        A=mul(A,A);
        y>>=1;
    }
    return ans;
}
inline int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int r=exgcd(b,a%b,x,y);
    
    int temp=x;
    x=y;
    y=temp-a/b*y;
    return r;
} 
int main()
{
    cin>>k>>p;
    base.m[1][1]=1,base.m[1][2]=1,base.m[2][1]=1,base.m[2][2]=0;
    base=quickpow(base,k+1);
    int fibn=base.m[2][1];
    
    
    int x,y;
    if(exgcd(fibn,p,x,y)!=1)    cout<<"None";
    else cout<<(x%p+p)%p;
    return 0;
}