前四位我們可以算出d[1]=2,d[2]=4,d[3]=6,d[4]=9.
我們可以這樣想:一個合法串可以由兩個較短的合法串組成
就以d[n]為例:(注意不能重複)
1、n-1個字元的時候: +m
2、n-2: 只能+mm,會和n-1重複,所以不考慮n-2
3、n-3: +mmf
4、n-4: +mmff
5、n-5: 如果是+mmffm,會與n-1重複,+mmmff會與n-4重複,+mmmmf會與n-3重複(不考慮)
所以就考慮n-1,n-3,n-4,DP等式就出來了:dp[n]=dp[n-1]+dp[n-3]+dp[n-4]
矩陣快速冪
#include <map>#include <set>#include <list>#include <queue>#include <deque>#include <stack>#include <string>#include <time.h>#include <cstdio>#include <math.h>#include <iomanip>#include <cstdlib>#include <limits.h>#include <string.h>#include <iostream>#include <fstream>#include <algorithm>using namespace std;#define LL long long#define MIN INT_MIN#define MAX INT_MAX#define PI acos(-1.0)#define FRE freopen("input.txt","r",stdin)#define FF freopen("output.txt","w",stdout);int MOD ;#define n 4struct Mat{ int mat[4][4];};//初始化單位矩陣Mat init(){ Mat E; for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ if(i == j) E.mat[i][i] = 1; else E.mat[i][j] = 0; } } return E;}//重載乘法Mat operator *(Mat a,Mat b){ Mat c; memset(c.mat,0,sizeof(Mat)); for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ for(int k = 0; k < n; k++){ if(a.mat[i][k] && b.mat[k][j]){ c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % MOD; } } } } return c;}//重載加法Mat operator +(Mat a,Mat b){ Mat c; memset(c.mat,0,sizeof(Mat)); for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ c.mat[i][j] = (a.mat[i][j] + b.mat[i][j]) % MOD; } } return c;}//重載冪次方Mat operator ^(Mat A,LL x){ if(x == 1)return A; Mat c; c = init(); for(; x ; x >>= 1){ if(x&1){ c = c*A; } A = A*A; } return c;}int main(){ int l,m; int f[4] = {2,4,6,9}; Mat gao = {1,0,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0}; while(scanf("%d%d",&l,&m)!=EOF){ if(!l){ printf("0\n"); } else if(l<=4) printf("%d\n",f[l-1]); else{ MOD = m; Mat ans = gao^(l-4); int res = ans.mat[0][0]*9 + ans.mat[0][1]*6 + ans.mat[0][2]*4 + ans.mat[0][3]*2; printf("%d\n",res%m); } } return 0;}