我们可以通过在一串序列的末尾不断添加'(f)'或是'(m)'来获得所有的串,其中我们要及时去除不合法的串'(fff)','(fwf)'
首先把所有的串分类,按照最末尾两个字符分四类,分别是,'(ff)','(fm)','(mf)','(mm)'
分别用(a_1),(a_2),(a_3),(a_4)来表示每种类别对应串的数量。
[
left[
egin{array}{ccc}
a_1\\
a_2\\
a_3\\
a_4\\
end{array}
ight]
*
left[
egin{array}{ccc}
1 & 0 & 1 & 0\\
1 & 0 & 1 & 0\\
0 & 1 & 0 & 1\\
0 & 1 & 0 & 1\\
end{array}
ight]
left[
egin{array}{ccc}
a'_1\\
a'_2\\
a'_3\\
a'_4\\
end{array}
ight]
]
注意,上面的式子是包括所有的转移的,其中有两种不合法的转移未删去。下面是最终转移。
[
left[
egin{array}{ccc}
a_1\\
a_2\\
a_3\\
a_4\\
end{array}
ight]
*
left[
egin{array}{ccc}
0 & 0 & 1 & 0\\
1 & 0 & 1 & 0\\
0 & 0 & 0 & 1\\
0 & 1 & 0 & 1\\
end{array}
ight]
left[
egin{array}{ccc}
a'_1\\
a'_2\\
a'_3\\
a'_4\\
end{array}
ight]
]
答案等于([1,1,1,1] *) 转移矩阵 得到的([ans_1,ans_2,ans_3,ans_4]),四个数相加即可
#include<bits/stdc++.h>
using namespace std;
int l,mod;
struct jz{
int g[10][10];
void init(){
memset(g,0,sizeof(g));
}
void one(){
memset(g,0,sizeof(g));
for(int i = 1; i <= 4; ++ i) g[i][i] = 1;
}
};
jz operator * (jz a, jz b){
jz c; c.init();
for(int i = 1; i <= 4; ++ i)
for(int j = 1; j <= 4; ++ j)
for(int k = 1; k <= 4; ++ k)
c.g[i][j] += a.g[i][k] * b.g[k][j] % mod, c.g[i][j] %= mod;
return c;
}
jz ksm(jz x,int y){
jz z; z.one();
while(y){
if(y & 1) z = z * x;
y >>= 1;
x = x * x;
}
return z;
}
int qpow(int x,int y){
int z = 1;
while(y){
if(y & 1) z = 1ll * z * x % mod;
y >>= 1;
x = 1ll * x * x % mod;
}
return z;
}
jz a;
int main(){
while(scanf("%d%d",&l,&mod) != EOF){
a.init();
a.g[1][4] = 1;
a.g[2][1] = a.g[2][4] = 1;
a.g[3][2] = a.g[3][3] = 1;
a.g[4][3] = 1;
//a.g[5][1] = a.g[5][2] = a.g[5][5] = 1;
if(l <= 2) { printf("%d
",qpow(2,l)); continue; }
l -= 2;
a = ksm(a,l);
int ans = 0;
for(int i = 1; i <= 4; ++ i)
for(int j = 1; j <= 4; ++ j)
ans += a.g[i][j] , ans %= mod;
printf("%d
",ans);
}
return 0;
}
/*
a1 ff 0001 ff
b1 fm 1001 fm
a2 mm 0110 mm
b2 mf 0010 mf
*/