前四位我们可以算出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]
矩阵快速幂
我们可以这样想:一个合法串可以由两个较短的合法串组成
就以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 4
struct 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;
}
本文详细阐述了如何使用动态规划解决序列问题,通过构建状态转移方程和矩阵快速幂加速计算过程,提供了求解复杂序列问题的有效策略。

被折叠的 条评论
为什么被折叠?



