面对这样一道题目,最容易想到的就是动态规划了。首先我们用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; }