LibreOJ # 3086. 「GXOI / GZOI2019」逼死強迫症 【矩陣快速冪】

題目鏈接

題目大意:用n-1個1X2的格子和2個1X1的格子鋪成nX2的格子,要求2個1X1的格子不能相鄰。(n <= 1e9, 結果取模1e9+7)

題解:

如果沒有沒有兩個1X1的格子,則答案就是斐波拉契數列,當加入了兩個1X1的格子後,我們需要在遞推的時候考慮放1X1的格子的情況。假設答案爲 g[n] ,斐波拉契數列爲 f[n], 斐波拉契數列的和爲S[n].

所以當g[n] = (g[n-1] + g[n-2])(兩個1X1都不在新加入的格子) + 2*S[n-3](當有1個1X1在新加入的格子即第n個1X2,另一個可能在1...n-2,由於連個1X1之間的放置方法是固定的,所以總的方法數位f[1] + f[2] + f[3] + ... + f[n-3]),

又因爲S[n-3] = f[n-1] - 1  所以g_{i} = g_{i-1} + g_{i-2} + 2* f_{i-1} - 2

所以可以用矩陣快速冪,係數矩陣爲$$ \left[ \begin{matrix} g_{i}\\ g_{i-1}\\ f_{i-1}\\ f_{i-2}\\ -2 \end{matrix} \right] $$ = $$ \left [ \begin{matrix} 1&1&2&2&1\\ 1&0&0&0&0\\ 0&0&1&1&0\\ 0&0&1&0&0\\ 0&0&0&0&1 \end{matrix} \right ] $$ * $$ \left[ \begin{matrix} g_{i-1}\\ g_{i-2}\\ f_{i-2}\\ f_{i-3}\\ -2 \end{matrix} \right] $$   初始值g_{1} = 1, g_{0} = 1,f_{2} = 2, f_{1} = 1, f_{0} = 1

代碼:

#include<bits/stdc++.h>
using namespace std;

const int mod = 1e9+7;

struct Matrix{
  int a[5][5];
  Matrix operator *(const Matrix &b) const
  {
    Matrix res;
    memset(res.a, 0 ,sizeof(res.a));
    for(int i = 0; i < 5; i++)
    for(int j = 0; j < 5; j++)
    for(int k = 0; k < 5; k++)
      res.a[i][j] = (res.a[i][j] + (1LL* a[i][k] * b.a[k][j])%mod)%mod;
    return res;
  }
  void put()
  {
    for(int i = 0; i < 5; i++)
     {
       for(int j = 0; j < 5; j++)
       cout << a[i][j] << " ";
       cout << endl;
     }

  }
};

Matrix mfpow(Matrix x, int n)
{
  if(n <= 0) return x;
  Matrix res;
  memset(res.a,0,sizeof(res.a));
  for(int i = 0; i < 5; i++) res.a[i][i] = 1;
  while(n)
  {
    //x.put();
    //cout << n <<"***"<< endl;
    if(n&1) res = res * x;
    x = x * x;
    n >>= 1;
  }
  return res;
}

int main()
{
  int T;
  scanf("%d",&T);
  while(T--)
  {
  int n;
  scanf("%d",&n);
  Matrix st;
  int b[5][5] = {{1,1,2,2,1},{1,0,0,0,0},{0,0,1,1,0},{0,0,1,0,0},{0,0,0,0,1}};
  for(int i = 0; i < 5; i++) for(int j = 0; j < 5; j++) st.a[i][j] = b[i][j];
  Matrix ed = mfpow(st,n-1);
  int res = (0LL + ed.a[1][2] + ed.a[1][3] - ed.a[1][4]*2 + 2*mod)%mod;
  printf("%d\n",res);
}
  return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章