BZOJ 1009 HNOI 2008 GT考试 递推+矩乘
1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3679 Solved: 2254
[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
Solution
如果n很小的话,可以直接做数位DP,但是现在n很大,需要用到矩乘。
设F[i][j]表示准考证号前i位中匹配到不吉利数串的第j个的方案数。
我们很容易发现,F数组存在一定的转移关系。
转移时考虑当前匹配到不吉利串的第i个,下一个数字填0~9时,转移到匹配到不吉利串的第j个,匹配过程可以KMP,这样就可以构造出转移矩阵。
Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 7 using namespace std; 8 9 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i) 10 #define mset(a, b) memset(a, b, sizeof(a)) 11 const int maxn = 25; 12 int n, m, MOD; 13 char s[maxn]; 14 int nxt[maxn]; 15 struct Matrix 16 { 17 int mat[maxn][maxn]; 18 Matrix() { mset(mat, 0); } 19 Matrix operator * (const Matrix &AI) const 20 { 21 Matrix ret; 22 REP(i, 0, m-1) 23 REP(j, 0, m-1) 24 { 25 ret.mat[i][j] = 0; 26 REP(k, 0, m-1) (ret.mat[i][j] += mat[i][k]*AI.mat[k][j]) %= MOD; 27 } 28 return ret; 29 } 30 }A, B; 31 32 int main() 33 { 34 scanf("%d %d %d", &n, &m, &MOD); 35 scanf("%s", s+1); 36 int j = 0; nxt[1] = 0; 37 REP(i, 2, m) 38 { 39 while (j > 0 && s[j+1] != s[i]) j = nxt[j]; 40 if (s[j+1] == s[i]) j ++; 41 nxt[i] = j; 42 } 43 REP(i, 0, m-1) 44 REP(j, 0, 9) 45 { 46 int t = i; 47 while (t > 0 && s[t+1]-'0' != j) t = nxt[t]; 48 if (s[t+1]-'0' == j) t ++; 49 if (t != m) B.mat[t][i] = (B.mat[t][i]+1)%MOD; 50 } 51 REP(i, 0, m-1) A.mat[i][i] = 1; 52 while (n > 0) 53 { 54 if (n&1) A = A*B; 55 B = B*B; 56 n >>= 1; 57 } 58 int ans = 0; 59 REP(i, 0, m-1) ans = (ans+A.mat[i][0])%MOD; 60 printf("%d\n", ans); 61 return 0; 62 }
Nothing is impossible!