面对这样一道题目,最容易想到的就是动态规划了。首先我们用F[i][j]表示前i个数匹配到第j个的可行方案总数,这里F[i][j]可以从任何满足不吉利数字的第k-j+2位到第k位的不吉利数字全等于前j位的不吉利数字的F[i-1][k]转移过来。那么我们为了得出这样的一个解,我们枚举第i位所加上的数(从0到9),如果能匹配到一个位置,那么每次这个位置就要被匹配到的位置加上。特别注意匹配的j=0和加上同一个数字匹配到多个原答案的情况,这里我们只取最长的。
因为也在一边写一边学习,稍微借鉴了hzwer的程序。这里我们构造一个答案矩阵,即令
矩阵A*矩阵B=矩阵C
其中矩阵A是答案矩阵,矩阵B是上一次的一列答案,共一列,第i个数表示F[x][i]。矩阵C的第i个数则表示F[x+1][i]。我们现在就要构造矩阵A,可以通过之前所说的匹配关系来构造。
因为矩阵支持结合律的性质,我们利用矩阵快速幂,可以求出最终的答案。附代码:
#include "stdio.h"
#include "iostream"
#include "string.h"
using namespace std;
int n,m,mod,sum=0;
int c[30];
int p[30];
struct matrix{
int v[30][30];
int va,vb;
matrix():va(0),vb(0){memset(v,0,sizeof(v));}
matrix(int _l,int _r){va=_l,vb=_r;memset(v,0,sizeof(v));}
void ins(int i,int j,int ins){v[i][j]=(v[i][j]+ins)%mod;}
void dep(){for(int i=0;i<va;i++) v[i][i]=1;}
};
matrix operator * (matrix a,matrix b){
matrix c(a.va,b.vb);
int i,j,k;
for (i=0; i<a.va; i++){
for (j=0; j<b.vb; j++){
for (k=0; k<a.vb; k++){
c.ins(i,j,a.v[i][k]*b.v[k][j]);
}
}
}
return c;
}
matrix operator %(matrix q,int c){return q;}
template <class __Type>
void _pow(__Type a,int k,__Type &push){
while (k){
if (k%2){
push=push*a;
push=push%mod;
}
a=a*a;
a=a%mod;
k>>=1;
}
};
int main(){
scanf("%d%d%d",&n,&m,&mod);
int i,j;
for (i=1; i<=m; i++){
scanf("%1d",c+i);
}
for (i=2,j=0; i<=m; i++){
while (j>0&&c[j+1]!=c[i]) j=p[j];
if (c[i]==c[j+1])++j;
p[i]=j;
}
matrix sub(m,m);
for (i=0; i<m; i++){
int k;
for (k=0; k<10; k++){
j=i;
while (j>0&&c[j+1]!=k) { j=p[j]; }
if(c[j+1]==k) j++;
if(j!=m){
sub.ins(j,i,1);
}
}
}
matrix q(m,m);q.dep();
_pow(sub,n,q);
long long wh=0;
for (i=0; i<m; i++){
wh=(wh+q.v[i][0])%mod;
}
cout << wh << endl;
return 0;
}