题意:给你一个只由字符m和f组成的长度为L的序列,我们令存在子序列fmf或fff的序列为O-序列,其它的序列均为E-序列。现在让你求出K % M,其中K为长L的序列里面E-序列的数目。
思路:这道题需要先推出公式f(L) = f(L-1) + f(L-3) + f(L-4)。然后同求斐波那契数列的方式,构造矩阵,下面就是矩阵快速幂了。
公式推导:
我们考虑L长序列的最后一位字符C1
一:C1 = m,我们不用考虑前面L-1字符,直接有方案数f(L-1);
二:C1 = f,我们需要考虑L长序列的倒数第二个字符C2
1,C2 = m,因为末尾序列可能存在fmf的情况,我们需要考虑L长序列的倒数第三个字符C3
(1) C3 = m,得到末尾三个字符mmf,我们不用考虑mmf前面的字符,有方案数f(L-3);
(2) C4 = f,得到末尾三个字符fmf,不是E-序列。
2,C2 = f,因为末尾序列可能存在fff的情况,我们需要考虑L长序列的倒数第三个字符C3
(1) C3 = m,得到末尾三个字符mff,因为末尾序列可能存在fmff的情况,我们考虑倒数第四个字符C4
One C4 = m,得到末尾序列mmff,我们不用考虑mmff前面的字符,有方案数f(L-4);
TwoC4 = f,得到末尾序列fmff,不是E-序列。
(2) C4 = f,得到末尾三个字符fff,不是E-序列。
这样总方案数f(L) = f(L-1) + f(L-3) + f(L-4)。
下面就是构造矩阵了,给个图示
初始矩阵 F矩阵
构造矩阵后,求出初始矩阵的L-3次幂,最后再与F矩阵相乘得到结果矩阵Ans。最后的答案就是Ans[0]。
这里说的是L>3的情况,至于L <= 3的情况只需要注意L = 0时结果是0就行了。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 6 #define LL long long using namespace std; struct Matrix { int a[MAXN][MAXN]; int r, c; }; Matrix ori, res; int F[5];//F矩阵 int Ans[5];//结果矩阵 void init() { //构造矩阵 ori.r = ori.c = 4; memset(ori.a, 0, sizeof(ori.a)); ori.a[0][0] = ori.a[0][2] = ori.a[0][3] = 1; ori.a[1][0] = ori.a[2][1] = ori.a[3][2] = 1; //构造单位矩阵 res.r = res.c = 4; memset(res.a, 0, sizeof(res.a)); res.a[0][0] = res.a[1][1] = res.a[2][2] = res.a[3][3] = 1; //构造F矩阵 F[0] = 6, F[1] = 4, F[2] = 2, F[3] = 1; } Matrix muitl(Matrix x, Matrix y, int m) { Matrix z; memset(z.a, 0, sizeof(z.a)); z.r = x.r; z.c = y.c; for(int i = 0; i < x.r; i++) { for(int k = 0; k < x.c; k++) { if(x.a[i][k] == 0) continue; for(int j = 0; j < y.c; j++) z.a[i][j] = (z.a[i][j] + (x.a[i][k] * y.a[k][j]) % m) % m; } } return z; } void Matrix(int n, int m) { while(n) { if(n & 1) res = muitl(ori, res, m); ori = muitl(ori, ori, m); n >>= 1; } } void solve(int n, int m) { Matrix(n, m);//矩阵的n次幂 对m取余 memset(Ans, 0, sizeof(Ans)); for(int i = 0; i < res.r; i++) { for(int k = 0; k < res.c; k++) Ans[i] = (Ans[i] + res.a[i][k] * F[k]) % m; } printf("%d\n", Ans[0]); } int main() { int L, M; while(scanf("%d%d", &L, &M) != EOF) { Ans[0] = 0, Ans[1] = 2, Ans[2] = 4, Ans[3] = 6; if(L <= 3) { printf("%d\n", Ans[L] % M); continue; } init();//构造矩阵 solve(L-3, M); } return 0; }