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 ) ; }