思路
动态规划
我们可以先考虑当
n
的范围较小时的做法,设
很显然的是,需要枚举
i
位出现的数字是哪一个,枚举完数字以后,如果与不幸运数字匹配成功,那么匹配位数
状态转移方程:
f[i+1][trans[j][k]]+=f[i][j]
矩阵优化
当
n
的范围是
我们可以通过初始矩阵和目的矩阵来构造目标矩阵。
首先我们要把要转移的信息集中在一起,构造一个方阵让其转移,没有的地方补
0
就可以。
所以初始矩阵和转移矩阵都是
初始矩阵:
⎛⎝⎜⎜⎜⎜⎜f[i][0]0⋮0f[i][1]0⋮0⋯⋯⋱⋯f[i][m]0⋮0⎞⎠⎟⎟⎟⎟⎟
目标矩阵:
⎛⎝⎜⎜⎜⎜⎜f[i+1][0]0⋮0f[i+1][1]0⋮0⋯⋯⋱⋯f[i+1][m]0⋮0⎞⎠⎟⎟⎟⎟⎟
设转移矩阵为:
⎛⎝⎜⎜⎜⎜⎜a11a21⋮am1a12a22⋮am2⋯⋯⋱⋯a1ma2m⋮amm⎞⎠⎟⎟⎟⎟⎟
需要明确的是,初始矩阵中第一行第 i 列的数转移的条件应转移矩阵的第
对于一个 f[i][a] ,可以转移到 f[i+1][b] ,那么我们就在转移矩阵的第 a 行,第
如果 a=m ,说明是不吉利的数字,不转移。
代码
#include <iostream>
#include <cstdio>
using namespace std;
int f[50], x[50], trans[50][15], mod, n, m, p, res;
char ch[50];
struct Matrix{
int node[25][25];
Matrix(){
for(int i = 0; i <= 24; i ++) {
for(int j = 0; j <= 24; j ++){
node[i][j] = 0;
}
}
}
void init(){
for(int i = 0; i <= m; i ++) node[i][i] = 1;
}
Matrix operator * (const Matrix &M){
Matrix res;
for(int i = 0; i < m; i ++)
for(int j = 0; j < m; j ++)
for(int k = 0; k < m; k ++)
res.node[i][j] = (res.node[i][j] + node[i][k]*M.node[k][j]) % mod;
return res;
}
} w, ans, Begin;
Matrix pow(Matrix x, int y){
Matrix res;
res.init();
for( ; y; y >>= 1, x = x*x) if(y&1) res = res * x;
return res;
}
int main(){
scanf("%d%d%d", &n, &m, &mod);
scanf("%s", ch+1);
for(int i = 1; i <= m; i ++) x[i] = ch[i]-'0';
p = 0;
for(int i = 2; i <= m; i ++){
while(p && x[p+1] != x[i]) p = f[p];
if(x[p+1] == x[i]) p ++;
f[i] = p;
}
for(int i = 0; i < m; i ++){
for(int j = 0; j <= 9; j ++){
p = i;
while(p && x[p+1] != j) p = f[p];
if(x[p+1] == j) p ++;
trans[i][j] = p;
}
}
for(int i = 0; i < m; i ++){
for(int j = 0; j <= 9; j ++){
if(trans[i][j] != m) w.node[i][trans[i][j]] ++;
}
}
Begin.node[0][0] = 1;
ans = pow(w, n);
ans = Begin * ans;
for(int i = 0; i < m; i ++){
res = (res + ans.node[0][i]) % mod;
}
printf("%d", res);
return 0;
}