1. 程式人生 > >LOJ #10222. 「一本通 6.5 例 4」佳佳的 Fibonacci

LOJ #10222. 「一本通 6.5 例 4」佳佳的 Fibonacci

題目連結

題目大意

$$F[i]=F[i-1]+F[i-2]\ (\ F[1]=1\ ,\ F[2]=1\ )$$

$$T[i]=F[1]+2F[2]+3F[3]+...+nF[n]$$

求$T[n]\ mod\ m$

$n,m<=2^{31}-1$

 

這題的遞推式推導有點神仙,完全想不到多用兩個陣列來形成遞推式。研究了一下一本通上面的兩個輔助陣列的用途然後才會推出來這個轉移矩陣

還是太菜了

題解

由題目可得

 $$F[i]=F[i-1]+F[i-2]\ (\ F[1]=1\ ,\ F[2]=1\ )$$

$$T[i]=F[1]+2F[2]+3F[3]+...+nF[n]$$

然而$T[i]$並不可以形成遞推式,所以可以設

 $$nS[i]=nF[1]+nF[2]+nF[3]+...+nF[n]$$

\begin{align*}
p[i]&=nS[i]-T[i]\\
&=(n-1)F[1]+(n-2)F[2]+...+F[n]\\
&=p[i-1]+s[i-1]
\end{align*}

這個推導可以把$p[i-1]$和$S[i-1]$以及$p[i]$展開來,就可以很好理解為什麼可以這樣子化成遞推式了

於是我們就得到了一個遞推式

 $$p[i]=p[i-1]+s[i-1]$$

而答案即為$T[n]=nS[n]-p[N]$

有了遞推式就可以使用矩陣乘法優化:

轉移矩陣隨便推推就出來了,也不難推

$$\left[
\begin {matrix}
p[i]\\
S[i]\\
F[i]\\
F[i-1]
\end {matrix}
\right]
*
\left[
\begin{matrix}
1&1&0&0\\
0&1&1&0\\
0&0&1&1\\
0&0&1&0
\end{matrix}
\right]
=
\left[
\begin{matrix}
p[i+1]\\
S[i+1]\\
F[i+1]\\
F[i]
\end{matrix}
\right]$$

然後就是套板子了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <map>

using namespace std ;

#define I_int int
inline I_int read() {
    I_int x = 0 , f = 1 ; char c = getchar() ;
    while( c < '0' || c > '9' ) {
        if( c == '-' ) f = -1 ;
        c = getchar() ;
    }
    while( c >= '0' && c <= '9' ) {
        x = x * 10 + c -'0' ;
        c = getchar() ;
    }
    return x * f ;
}
#undef I_int

#define ll long long
#define inf 0x3f3f3f3f
#define in(a) a = read()
#define out(a) printf( "%d " , a )
#define outn(a) printf( "%d\n" , a )
#define N 100010

ll mod ;
struct matrix {
    ll m[ 5 ][ 5 ] ;
    matrix() { memset( m , 0 , sizeof( m ) ) ; }
    ll *operator[] ( ll a ) { return m[ a ] ; }
    matrix operator * ( matrix &x ) {
        matrix ans ;
        memset( ans.m , 0 , sizeof( ans.m ) ) ;
        for( int i = 0 ; i < 4 ; i ++ ) {
            for( int j = 0 ; j < 4 ; j ++ ) {
                for( int k = 0 ; k < 4 ; k ++ ) {
                    ans[ i ][ j ] = ( ans[ i ][ j ] + m[ i ][ k ] * x[ k ][ j ] % mod ) % mod ;
                }
            }
        }
        return ans ;
    }
} A , B ;

int n = read() ;

void init() {
    A[0][0]=A[0][1]=A[1][1]=A[1][2]=A[2][2]=A[2][3]=A[3][2]=1;
    B[1][0]=B[2][0]=B[3][0]=1;
}

matrix power( ll p ) {
    matrix ans , base = A ;
    for( int i = 0 ; i < 4 ; i ++ ) ans[ i ][ i ] = 1 ;
    while( p ) {
        if( p & 1 ) ans = ans * base ;
        base = base * base ;
        p >>= 1 ;
    }
    return ans ;
}

int main() {
    scanf( "%lld" , &mod ) ;
    init() ;
    A = power( n - 1 ) ;
    matrix ans = A * B ;
    printf( "%lld\n" , (n*ans[1][0]-ans[0][0]+mod)%mod ) ;
}