题目链接:
https://vjudge.net/problem/HDU-2604
题目大意:
n个人排队,f表示女,m表示男,包含子串‘fmf’和‘fff’的序列为O队列,否则为E队列,有多少个序列为E队列。
解题思路:
用f(n)表示n个人满足条件的结果,那么如果最后一个人是m的话,那么前n-1个满足条件即可,就是f(n-1);
如果最后一个是f那么这个还无法推出结果,那么往前再考虑一位:那么后三位可能是:mmf, fmf, mff, fff,其中fff和fmf不满足题意所以我们不考虑,但是如果是
mmf的话那么前n-3可以找满足条件的即:f(n-3);如果是mff的话,再往前考虑一位的话只有mmff满足条件即:f(n-4)
所以f(n)=f(n-1)+f(n-3)+f(n-4),递推会超时,可用矩阵快速幂
构造一个矩阵:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int MOD; 4 struct Mat 5 { 6 int a[4][4]; 7 int n, m;//n为行数,m为列数 8 Mat(int n, int m):n(n), m(m) 9 { 10 memset(a, 0, sizeof(a)); 11 } 12 void init() 13 { 14 for(int i = 0; i < n; i++)a[i][i] = 1;//初始化成单位矩阵 15 } 16 void output() 17 { 18 for(int i = 0; i < n; i++) 19 { 20 for(int j = 0; j < m; j++) 21 { 22 cout<<a[i][j]<<" "; 23 } 24 cout<<endl; 25 } 26 } 27 }; 28 Mat mul(Mat a, Mat b)//矩阵乘法 29 { 30 Mat tmp(a.n, b.m);//矩阵乘法结果矩阵行数为a的行数,列数为b的列数 31 for(int i = 0; i < a.n; i++) 32 { 33 for(int j = 0; j < b.m; j++) 34 { 35 for(int k = 0; k < a.m; k++)//a.m == b.n(乘法的前提条件) 36 { 37 tmp.a[i][j] += (a.a[i][k] * b.a[k][j] % MOD); 38 tmp.a[i][j] %= MOD; 39 } 40 } 41 } 42 return tmp; 43 } 44 Mat pow(Mat a, int n) 45 { 46 Mat tmp(a.n, a.m); 47 tmp.init(); 48 while(n) 49 { 50 if(n & 1)tmp = mul(tmp, a); 51 n /= 2; 52 a = mul(a, a); 53 } 54 return tmp; 55 } 56 int c[4][4] = 57 { 58 1,0,1,1, 59 1,0,0,0, 60 0,1,0,0, 61 0,0,1,0, 62 }; 63 int t[] = {0,2,4,6,9}; 64 int main() 65 { 66 Mat a(4, 4); 67 Mat b(4, 1); 68 memcpy(a.a, c, sizeof(c)); 69 for(int i = 0; i < 4; i++)b.a[i][0] = t[4 - i]; 70 //a.output(); 71 //b.output(); 72 int n ,k; 73 while(cin >> n >> k) 74 { 75 MOD = k; 76 if(n <= 4) 77 { 78 cout<<t[n]%k<<endl; 79 } 80 else 81 { 82 Mat ans = pow(a, n - 4); 83 ans = mul(ans, b); 84 //ans.output(); 85 cout<<ans.a[0][0]<<endl; 86 } 87 } 88 }