 /**//*
题意:求长度为L的合法串,非法只包含fmf,fff
画一下DFA,可知长度为L的合法串可由长度较短的合法串过来
(看从安全到安全状态的回路是怎样即可,注意这个路径也不能使其他状态走到非法的!去掉重复的)
+m,+mmf,+mmff
dp[L] = dp[L-1]+dp[L-3]+dp[L-4]
注意dp[0]未定义!!
所以要初始化dp[1 4] ,dp[4]=9
M<=30,可以打表 ,不过要开成char类型,int会MLE
不打表很慢
可以用矩阵二分
*/
#include<cstdio>
#include<cstring>

char dp[1000001][31];

int main()
  {
int L,M;
 for(M=1;M<=30;M++) {
dp[1][M]=2%M,dp[2][M]=4%M,dp[3][M]=6%M,dp[4][M]=9%M;
for(L=5;L<=1000000;L++)
dp[L][M]=(dp[L-1][M]+dp[L-3][M]+dp[L-4][M])%M;
}
while(~scanf("%d%d",&L,&M))
printf("%d\n",dp[L][M]);
return 0;
}

 /**//*
Matrix 二分版
*/
#include<cstdio>
#include<cstring>

int MOD,L;

 int ANS[4][4],A[4][4]= {
1,1,0,0,
0,0,1,0,
1,0,0,1,
1,0,0,0
};

void mul(int A[][4],int B[][4])
  {
int R[4][4];
memset(R,0,sizeof(R));
for(int k=0;k<4;k++)
for(int i=0;i<4;i++)
if(A[i][k])
for(int j=0;j<4;j++)
R[i][j]=(R[i][j]+A[i][k]*B[k][j])%MOD;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
A[i][j]=R[i][j];
}
void power(int m[][4],int n)
  {
if(n==1)
 {
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
m[i][j]=A[i][j];
return;
}
power(m,n/2);
mul(m,m);
if(n&1)mul(m,A);
}
int main()
  {
while(~scanf("%d%d",&L,&MOD))
 {
 int num[5] = {0,2,4,6,9};
if(L<=4)printf("%d\n",num[L]%MOD);
else
 {
power(ANS,L-4);
int ans = 0;
for(int i=0;i<4;i++)
ans+=num[4-i]*ANS[i][0];
printf("%d\n",ans%MOD);
}
}
return 0;
}

|