矩阵(板子)


一、前言

//一些矩阵乘法


二、算法

<1>P3390 (【模板】矩阵快速幂)

题解:
给定一个矩阵,求它的k次方
因为矩阵本身的乘法运算满足交换律和结合律,所以思考发现也应该满足快速幂的二的幂次相乘的规律。
对应一般的快速幂,写一个矩阵快速幂的函数,重新定义乘法,注意传参问题即可。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long

const int mod = 1e9+7;
const int N = 110;
int n,k;
int a[N][N];

int qpow(int base,int power) {
   int res = 1;
   while(power) {
       if(power & 1) res = res*base%mod;
       base = base*base%mod;
       power >>= 1;
   }return res;
}//一般快速幂

void chen(int ra[][N],int rb[][N]) {
   int ls[N][N];
   for (int i = 1; i <= n; i++) {
       for (int j = 1; j <= n; j++) {
           for (int lk = 1; lk <= n; lk++) {
               ls[i][j] += (ra[i][lk]*rb[lk][j]%mod);
               ls[i][j] %= mod;
               //cout << ra[i][lk] << ' ' << rb[lk][j] << endl;
           }//cout << i << '/' << j << endl;
       }
   }

   for (int i = 1; i <= n; i++) {
       for (int j = 1; j <= n; j++) {
           ra[i][j] = ls[i][j];
           ls[i][j] = 0;
       }
   }
}//矩阵乘法方式,ra数组会被传回去

int ans[N][N];
void qpow_jz(int power) {
   while(power) {
       if(power & 1) chen(ans,a);
       chen(a,a);
       power >>= 1;
   }return ;
}//求矩阵a的power次方

void solve() {
   cin >> n >> k;
   for (int i = 1; i <= n; i++) {
       for (int j = 1; j <= n; j++) {
           cin >> a[i][j];
       }
   }

   for (int i = 1; i <= n; i++) {
       ans[i][i] = 1;
   }//单位矩阵

   qpow_jz(k);
   for (int i = 1; i <= n; i++) {
       for (int j = 1; j <= n; j++) {
           cout << ans[i][j] << ' ';
       }cout << endl;
   }
}

signed main() {
   ios::sync_with_stdio(false);
   cin.tie(0); cout.tie(0);
   int _ = 1;
   //cin >> _;
   while(_--) solve();
}

<2> P1939 (矩阵加速(数列))

题解:
给了一个f数组的递推式,要求第n项,n高达2e9.
真是没想到跟矩阵有什么关系,看了题解发现可以考虑整体递推,这样就是一个不断相乘的过程。
【f[3],f[2],f[1]】(竖着摆放)
f[4] = f[3]+f[1]
f[3] = f[3]
f[2] = f[2]
根据矩阵相乘的规律,可以得到矩阵A
[1,0,1
1,0,0
0,1,0]
这是一次递推式,如果需要多次递推,也就是矩阵A的快速幂,快速幂n次之后发现ans[2][1]就是所需要的答案。

代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long

const int mod = 1e9+7;
const int N = 5;
int n = 3;
int k;
int a[N][N];

int qpow(int base,int power) {
  int res = 1;
  while(power) {
      if(power & 1) res = res*base%mod;
      base = base*base%mod;
      power >>= 1;
  }return res;
}//一般快速幂

void chen(int ra[][N],int rb[][N]) {
  int ls[N][N];
  memset(ls,0,sizeof ls);
  for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= n; j++) {
          for (int lk = 1; lk <= n; lk++) {
              ls[i][j] += (ra[i][lk]*rb[lk][j]%mod);
              ls[i][j] %= mod;
              //cout << ra[i][lk] << ' ' << rb[lk][j] << endl;
          }//cout << i << '/' << j << endl;
          //cout << ls[i][j] << endl;
      }
  }

  for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= n; j++) {
          ra[i][j] = ls[i][j];
          ls[i][j] = 0;
      }
  }
}

int ans[N][N];
void qpow_jz(int power) {
  //求矩阵a的power次方
  while(power) {
      if(power & 1) chen(ans,a);
      chen(a,a);
      power >>= 1;
  }return ;
}

void solve() {
  cin >> k;

  if(k <= 3) {
      cout << 1 << endl;
      return ;
  }

  memset(a,0,sizeof a);
  memset(ans,0,sizeof a);
  a[1][1] = a[1][3] = a[2][1] = a[3][2] = 1;

  for (int i = 1; i <= n; i++) {
      ans[i][i] = 1;
  }//单位1

  qpow_jz(k);
  cout << ans[2][1] << endl;

}

signed main() {
  ios::sync_with_stdio(false);
  cin.tie(0); cout.tie(0);
  int _ = 1;
  cin >> _;
  while(_--) solve();
}

<3> P1306 (斐波那契公约数)

题解:
主要需要考虑到一开始的n就会超过1e8,所以直接mod 会有误差,经过一系列推算,发现先求公约数再算斐波那契数和原本所要求的是一样的,所以计算出转移矩阵后用矩阵快速幂即可。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long

const int mod = 1e8;
const int N = 5;
int n = 2;
int k;
int a[N][N];

int qpow(int base,int power) {
    int res = 1;
    while(power) {
        if(power & 1) res = res*base%mod;
        base = base*base%mod;
        power >>= 1;
    }return res;
}//一般快速幂

void chen(int ra[][N],int rb[][N]) {
    int ls[N][N];
    memset(ls,0,sizeof ls);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            for (int lk = 1; lk <= n; lk++) {
                ls[i][j] += (ra[i][lk]*rb[lk][j]%mod);
                ls[i][j] %= mod;
                //cout << ra[i][lk] << ' ' << rb[lk][j] << endl;
            }//cout << i << '/' << j << endl;
            //cout << ls[i][j] << endl;
        }
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            ra[i][j] = ls[i][j];
            ls[i][j] = 0;
        }
    }
}

int ans[N][N];
void qpow_jz(int power) {
    //求矩阵a的power次方
    while(power) {
        if(power & 1) chen(ans,a);
        chen(a,a);
        power >>= 1;
    }return ;
}

int gcd(int x,int y) {
    return y ? gcd(y,x%y):x;
}

int rx,ry;

void solve() {
    cin >> rx >> ry;
    int k = gcd(rx,ry);

    if(k <= 2) {
        if(rx == 0) rx = 1;
        else ry = 1;
        return ;
    }

    memset(a,0,sizeof a);
    memset(ans,0,sizeof a);
    a[1][1] = a[1][2] = a[2][1] = 1;

    for (int i = 1; i <= n; i++) {
        ans[i][i] = 1;
    }//单位1

    qpow_jz(k);
//    for(int i = 1; i <= n; i++) {
//        for (int j = 1; j <= n; j++) {
//            cout << ans[i][j] << ' ';
//        }cout << endl;
//    }
     cout << ans[2][1] << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int _ = 1;
   // cin >> _;
    while(_--) solve();
}

三、总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值