首页 > 代码库 > BZOJ 1009 HNOI 2008 GT考试 递推+矩乘

BZOJ 1009 HNOI 2008 GT考试 递推+矩乘

1009: [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 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

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 }
View Code

 

 

 

 

 

BZOJ 1009 HNOI 2008 GT考试 递推+矩乘