1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MB Submit: 4024 Solved: 2452 [Submit][Status][Discuss]Description
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。 他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为 0
Input
第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
111
Sample Output
81
设$dp[i][j]$表示前i个字符,且后缀为不吉利数字的前缀的最长长度为j的方案数,那么显然$ans = sum_{i=1}^{m-1} dp[n][i]$
设$num[i][j]$为在长度为$i$的不吉利数字的前缀后加一个数使得后缀为不吉利数字的前缀的最长长度为$j$的方案数,$num$数组可以用kmp求出来
转移为$dp[k][j] = sum_{i = 1}^{m - 1} dp[k -1][i] * num[i][j]$
对于同一串不吉利数字$num$数组为常数,那么可以利用矩阵加速递推
#include <cstdio> #include <cstring> const int maxm = 25; int mod; struct matrix{ int n, m, num[maxm][maxm]; matrix(){} matrix(int _n, int _m){ n = _n; m = _m; memset(num, 0, sizeof num); } matrix operator * (const matrix &a){ matrix b(n, a.m); for(int i = 0; i < n; i++) for(int j = 0; j < a.m; j++) for(int k = 0; k < m; k++) (b.num[i][j] += num[i][k] * a.num[k][j]) %= mod; return b; } }; matrix ksm(matrix a, int b){ matrix s(a.m, a.m); for(int i = 0; i < s.m; i++) s.num[i][i] = 1; while(b){ if(b & 1) s = s * a; b >>= 1; a = a * a; } return s; } int n, m; char A[maxm]; int p[maxm]; int main(){ scanf("%d %d %d", &n, &m, &mod); scanf("%s", A + 1); p[1] = 0; for(int j = 0, i = 2; i <= m; i++){ while(A[i] != A[j + 1] && j) j = p[j]; if(A[i] == A[j + 1]) j++; p[i] = j; } matrix ans(1, m), zy(m, m); for(int i = 0; i < m; i++) for(int j = '0'; j <= '9'; j++){ int k = i; while(k && A[k + 1] != j) k = p[k]; if(A[k + 1] == j) k++; if(k != m) zy.num[i][k]++; } ans.num[0][0] = 1; ans = ans * ksm(zy, n); int aa = 0; for(int i = 0; i < m; i++) (aa += ans.num[0][i]) %= mod; printf("%d ", aa); return 0; }