1. 程式人生 > >矩陣快速冪(共軛函式)

矩陣快速冪(共軛函式)

題目連結:https://cn.vjudge.net/contest/261339#problem/A

具體思路:一開始看到這個題,覺得用快速冪就能很簡單的求出來,結果發現,要是想用快速冪的話,每次計算必然會損失一定的精度,並且取餘的時候必須進行強制轉換,所以這個方法絕對不行。

然後就開始想用矩陣快速冪,然後死活推不出公式來,然後看了網上的思路,果然不是一般人能想出來的。

首選觀看資料範圍,(a-1)^2< b < a ^2,所以  0 < (a- sqrt(b)) < 1,所以這就是一個很好的輔助工具,因為題目中說的是向下取餘,具體的作用後面說。  令 A(n)= ( a + sqrt(b) ) ^ n,B(n) = (a - sqrt(b) ) ^ n,也就是說,B是A的共軛函式,然後因為資料範圍的原因,我們就可以近似認為B(n)為0. 令 C( n )= A(n) + B(n) 。所以C(n)近似等於A(n)。然後開始推公式。(這是大神的手寫)

 

c(n)=a(n)+b(n)=a(n)

c(n)*((a+sqrt(b))+(a-sqrt(b))=c(n+1)+(a*a-b)*c(n-1).這樣矩陣就構造出來了。

{ 2*a    b-a*a  }

{1             0     }

AC程式碼:

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<stdio.h>
#include<iomanip>
#include<algorithm>
using namespace std;
# define ll long long
ll a,b,n,m;
struct Matrix
{
    ll ai[5][5];
    Matrix operator *(Matrix temp)
    {
        Matrix ti;
        for(int i=1; i<=2; i++)
        {
            for(int j=1; j<=2; j++)
            {
                ti.ai[i][j]=0;
                for(int k=1; k<=2; k++)
                {
                    ti.ai[i][j]+=(ai[i][k]%m)*(temp.ai[k][j]%m)%m;
                    ti.ai[i][j]%=m;
                }
            }
        }
        return ti;
    }
};
ll quickpow(Matrix ti,ll t2)
{
    Matrix temp=ti;
    t2--;
    while(t2)
    {
        if(t2&1)temp=temp*ti;
        ti=ti*ti;
        t2>>=1;
    }
    return (temp.ai[1][1]*2*a%m+temp.ai[1][2]*2%m+m)%m;
}
int main()
{
    while(~scanf("%lld%lld%lld%lld",&a,&b,&n,&m))
    {
        Matrix temp;
        temp.ai[1][1]=2*a%m;
        temp.ai[1][2]=(b-a*a%m)%m;
        temp.ai[2][1]=1;
        temp.ai[2][2]=0;
        ll w=2*a%m;
        if(n==1)printf("%lld\n",w);
        else{
        ll ans=quickpow(temp,n-1)%m;
        printf("%lld\n",ans);
        }
    }
    return 0;
}