1. 程式人生 > 實用技巧 >矩陣快速冪-1246

矩陣快速冪-1246

題目大意:

思路:

  看到這麼高的資料複雜度肯定要log級別的演算法才可以過,所以肯定有遞推公式,我們可以從一個數字遞推一下看當前數字可以轉移到哪幾個數字,很容易發現出現了一個遞推矩陣,再看2個數字的情況,也是一樣的,但是要注意不要重複判定就行,就比如4-16-26-46-66-46這樣就會出現環,出現環就結束就行了,所以也可以寫出2個數字的遞推式,所以就可以構造一個遞推矩陣。能水過96分,但是大於等於3的情況比較多,先記錄一下,以後推出來補充

程式碼:

#include <iostream>
#include <cstring>
#include <vector>
using
namespace std; typedef long long ll; int v2id[70]; int b_e[]={1,2,4,6,16,26,41,42,44,46,61,62,64,66}; int f_t[][4]={{2},{4},{1,6,16},{6,4,64},{26},{46},{62},{64},{61},{66},{42},{44},{41},{46}}; const int mod=998244353; vector<vector<ll>> mul(vector<vector<ll>> a,vector<vector<ll>> b){
int n=a.size(); int kk=a[0].size(); int m=b[0].size(); vector<vector<ll>> res(n,vector<ll>(m,0)); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ for(int k=0;k<kk;k++){ res[i][j]+=((a[i][k]*1ll*b[k][j])%mod); res[i][j]
=res[i][j]%mod; } } } return res; } vector<vector<ll>> qmi(vector<vector<ll>> a,int n){ int r=a.size(); vector<vector<ll>> res(1,vector<ll>(r,0)); res[0][0]=1;//把2置為1表示第一個狀態 然後快速冪就行了 while(n){ if(n&1)res=mul(res,a); a=mul(a,a); n>>=1; } return res; } ll slove(int id,int n){ vector<vector<ll>> a(14,vector<ll>(14,0)); for(int i=0;i<14;i++){ for(int j=0;j<=3;j++){ if(f_t[i][j]==0)break; a[i][v2id[f_t[i][j]]]++; } } vector<vector<ll>> res=qmi(a,n); return res[0][id]%mod; } int main(){ memset(v2id,-1,sizeof v2id); for(int i=0;i<14;i++){ v2id[b_e[i]]=i; } int n; string s; cin>>n>>s; int num=0; for(int i=0;i<s.size();i++){ num*=10; num+=(s[i]-'0'); } if(s.size()<=2)cout<<slove(v2id[num],n)<<endl; else { // 還有一個測試樣例不知道咋搞遞推式 } }