小结
解决的问题:
解决递推关系中不好直接写出通项公式的问题,将多个递推关系的系数在矩阵中表示
而对于矩阵的幂运算可以用快速幂,复杂度:O(m^3*logn)
所以算法核心就是找到递推关系对应的矩阵辣
POJ 3420 Quad Tiling
题意:在一个4*n的棋盘上,用1*2的多米诺骨牌来平铺,问铺满的方法有多少种。
思路:这道题不能直接找到明显的递推关系,参考了网上一种 “ 不可分割 ” 拼凑法的概念,这样就可以建立起递推的关系 // 真是妙呀
当n为奇数且n>=3时,不可分割的平铺方法为2;当n为偶数且n>=4时,不可分割的平铺方法为3; 所以得到下列递推式: f(n)=f(n-1)+f(n-2)*4+f(n-3)*2+f(n-4)*3+…+f(0)*b(n) f(n)=f(n-1)+5*f(n-2)+f(n-3)-f(n-4)
f[n-3] 0 1 0 0 f[n-4] |
f[n-2] = 0 0 1 0 * f[n-3] |
f[n-1] 0 0 0 1 f[n-2] |
f[n] -1 1 5 1 f[n-1] |
再借用矩阵的模板就ac了
#include<iostream> #include<string.h> using namespace std; const int MAXN=10; const int MAXM=10; int r,mod; //矩阵类模板 struct Matrix{ int n,m; int a[MAXN][MAXM]; void clear(){ n=m=0; memset(a,0,sizeof(a)); } Matrix operator +(const Matrix &b) const { Matrix tmp; tmp.n=n;tmp.m=m; for (int i=0;i<n;++i) for(int j=0;j<m;++j) tmp.a[i][j]=a[i][j]+b.a[i][j]; return tmp; } Matrix operator -(const Matrix &b)const{ Matrix tmp; tmp.n=n;tmp.m=m; for (int i=0;i<n;++i) for(int j=0;j<m;++j) tmp.a[i][j]=a[i][j]-b.a[i][j]; return tmp; } Matrix operator * (const Matrix &b) const{ Matrix tmp; tmp.clear(); tmp.n=n;tmp.m=b.m; for (int i=0;i<n;++i) for(int j=0;j<b.m;++j) for (int k=0;k<m;++k){ tmp.a[i][j]+=a[i][k]*b.a[k][j]; tmp.a[i][j]%=mod; } return tmp; } Matrix get(int x){//幂运算 Matrix E; E.clear(); E.n=E.m=n; for(int i=0;i<n;++i) E.a[i][i]=1; if(x==0) return E; else if(x==1) return *this; Matrix tmp=get(x/2); tmp=tmp*tmp; if(x%2) tmp=tmp*(*this); return tmp; } }; int main(){ while(cin>>r>>mod){ if(r==0) break; int a[]= {1,1,5,11}; if(r<=3) { cout<<a[r]%mod<<endl; continue; } Matrix A; A.clear(); A.n=A.m=4; A.a[0][1]=A.a[1][2]=A.a[2][3]=1; A.a[3][0]=-1; A.a[3][1]=1; A.a[3][2]=5; A.a[3][3]=1; A=A.get(r-3); Matrix M; M.clear(); M.n=4;M.m=1; M.a[0][0]=M.a[1][0]=1; M.a[2][0]=5; M.a[3][0]=11; M=A*M; cout<<(M.a[3][0]+mod)%mod<<endl; } return 0; }
POJ 3735 Training little cats
题意:给了n,m,k分别代表有几只猫,同样的一套动作要做m次,这套动作有k个
有n只猫,给每只猫放食物:
g i 代表给第i只猫加一块食物
e i 代表第i只猫吃完自己的所有食物
s i j 代表第i只猫,与第j只猫的食物互换
问这一套动作,做m次,每个猫有多少食物
思路:显然是矩阵模板题,但是有一点就是这是一个稀疏矩阵,不能直接套用模板
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define ll long long #define maxn 105 int n, m, k; struct Mat { ll val[maxn][maxn]; void zero() { memset(val, 0, sizeof(val)); } void unit() { zero(); for(int i = 0; i < maxn; i++) val[i][i] = 1; } }A, T; Mat operator *(const Mat &a, const Mat &b) { Mat tmp; tmp.zero(); for(int k = 0; k <= n; k++) { for(int i = 0; i <= n; i++) { if(a.val[i][k]) for(int j = 0; j <= n; j++) tmp.val[i][j] += a.val[i][k] * b.val[k][j]; } } return tmp; } Mat operator ^(Mat x, int n) { Mat tmp; tmp.unit(); while(n) { if(n & 1) tmp = tmp * x; x = x * x; n >>= 1; } return tmp; } void init() { A.zero(); A.val[0][0] = 1; T.unit(); } int main() { char s[5]; int a, b; while(~scanf("%d%d%d", &n, &m, &k)) { if(!n && !m && !k) break; init(); for(int i = 0; i < k; i++) { scanf("%s", s); if(s[0] == 'g') { scanf("%d", &a); T.val[0][a]++; } else if(s[0] == 'e') { scanf("%d", &a); for(int i = 0; i <= n; i++) T.val[i][a] = 0; } else { scanf("%d%d", &a, &b); for(int i = 0; i <= n; i++) swap(T.val[i][a], T.val[i][b]); } } Mat ans = A * (T ^ m); for(int i = 1; i <= n; i++) printf("%lld ", ans.val[0][i]); printf(" "); } return 0; }
最新评论