zoukankan      html  css  js  c++  java
  • 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]$$

    egin{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[
    egin {matrix}
    p[i]\
    S[i]\
    F[i]\
    F[i-1]
    end {matrix}
    ight]
    *
    left[
    egin{matrix}
    1&1&0&0\
    0&1&1&0\
    0&0&1&1\
    0&0&1&0
    end{matrix}
    ight]
    =
    left[
    egin{matrix}
    p[i+1]\
    S[i+1]\
    F[i+1]\
    F[i]
    end{matrix}
    ight]$$

    然后就是套板子了

    #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
    " , 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*ans[1][0]-ans[0][0]+mod)%mod ) ;
    }
  • 相关阅读:
    跟踪创建类的个数
    动手动脑3
    动手动脑:随机数发生器和函数重载
    统计英语文章中单词
    动手动脑(1)
    原码、反码、补码
    java测试ATM自助操作系统
    深入浅出 TCP/IP 协议栈
    十大经典排序算法(动图演示)
    深入浅出 Viewport 设计原理
  • 原文地址:https://www.cnblogs.com/henry-1202/p/9932349.html
Copyright © 2011-2022 走看看