題目連結:https://nanti.jisuanke.com/t/16442
題意:
有個人在第一年送了你一對1歲的兔子。這種兔子剛生下來的時候算0歲,當它在2~10歲的時候,每年都會生下一對兔子,並且它在10歲那年生完兔子後就會掛掉。現在讓你算出第t年兔子的總數(不算那一年10歲的兔子)。
題解:
我們用一個1*10的矩陣代表某一年的兔子數量,第k列上的數字n代表今年有n只k歲的兔子。
那麼初始矩陣是這樣的:
接下來考慮怎樣構造特殊矩陣。
有兩個轉移關係:
第二年0歲的兔子數 = 第二年2~10歲的兔子數之和 = 今年1~9歲的兔子數之和
第二年k (1<=k<=10) 歲的兔子數 = 今年k-1歲的兔子數
也就是這樣轉移:
b[0] = a[1] + a[2] + ... + a[9]
b[1] = a[0]
b[2] = a[1]
...
b[9] = a[8]
b[10] = a[9]
那麼特殊矩陣也就出來了:
所以第t年的矩陣ans = 初始矩陣start * ( 特殊矩陣special ^ (t-1) )
優化:由於在整個過程中根本沒有用到每年10歲的兔子數量,所以可以省去初始矩陣的第10列,以及特殊矩陣的第10列&第10行。
AC Code:
#include <iostream> #include <stdio.h> #include <string.h> #define MAX_L 15 #define MOD 1000000007 using namespace std; struct Mat { int n; int m; long long v[MAX_L][MAX_L]; Mat() { memset(v,0,sizeof(v)); n=0; m=0; } }; int t; long long sum=0; Mat make_unit(int k) { Mat mat; mat.n=k; mat.m=k; for(int i=0;i<k;i++) { mat.v[i][i]=1; } return mat; } Mat make_start() { Mat mat; mat.n=1; mat.m=10; mat.v[0][1]=1; return mat; } Mat make_special() { Mat mat; mat.n=10; mat.m=10; for(int i=1;i<=9;i++) { mat.v[i][0]=1; mat.v[i-1][i]=1; } return mat; } Mat mul_mat(const Mat &a,const Mat &b) { Mat c; c.n=a.n; c.m=b.m; for(int i=0;i<a.n;i++) { for(int j=0;j<b.m;j++) { for(int k=0;k<a.m;k++) { c.v[i][j]+=(a.v[i][k]*b.v[k][j])%MOD; c.v[i][j]%=MOD; } } } return c; } Mat quick_pow_mat(Mat mat,long long k) { Mat ans; ans=make_unit(mat.n); while(k) { if(k&1) { ans=mul_mat(ans,mat); } k>>=1; mat=mul_mat(mat,mat); } return ans; } void read() { cin>>t; } void solve() { Mat start=make_start(); Mat special=make_special(); Mat ans=mul_mat(start,quick_pow_mat(special,t-1)); for(int i=0;i<=9;i++) { sum=(sum+ans.v[0][i])%MOD; } } void print() { cout<<sum<<endl; } int main() { read(); solve(); print(); }