BZOJ1009: [HNOI2008]GT考试
1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4474 Solved: 2763
[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
HINT
Source
【题解】
不妨设dp[i][j]表示前i个字符,后缀有j个匹配上了,其余的没有匹配上
他们说做多了AC自动机上DP就能想出这个状态。。
可我还没写过AC自动机的题
预处理a[i][j]表示长度为i的前缀加上一个字符到达长度为j的前缀的方案数
转移为dp[i][j] = Σdp[i-1][k] * a[k][j]
很明显的矩阵乘法
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #include <cmath> 9 #define min(a, b) ((a) < (b) ? (a) : (b)) 10 #define max(a, b) ((a) > (b) ? (a) : (b)) 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 12 inline void swap(int &a, int &b) 13 { 14 long long tmp = a;a = b;b = tmp; 15 } 16 inline void read(int &x) 17 { 18 x = 0;char ch = getchar(), c = ch; 19 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 20 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 21 if(c == '-') x = -x; 22 } 23 24 const int INF = 0x3f3f3f3f; 25 const int MAXM = 30; 26 27 int a[MAXM][MAXM], p[MAXM][MAXM], nxt[MAXM], k, n, m; 28 char s[MAXM]; 29 30 void kmp() 31 { 32 nxt[0] = -1; 33 for(register int i = 1, j = -1;i < m;++ i) 34 { 35 while(j >= 0 && s[i] != s[j + 1]) j = nxt[j]; 36 if(s[i] == s[j + 1]) ++ j; 37 nxt[i] = j; 38 } 39 for(register int i = 0;i < m;++ i) 40 for(register int j = '0';j <= '9';++ j) 41 { 42 int tmp = i - 1; 43 while(tmp >= 0 && s[tmp + 1] != j) 44 tmp = nxt[tmp]; 45 if(s[tmp + 1] == j) ++ a[i][tmp + 2]; 46 else ++ a[i][0]; 47 } 48 } 49 50 int tmp[MAXM][MAXM], base[MAXM][MAXM]; 51 52 void pow(int b) 53 { 54 for(register int i = 0;i < m;++ i) 55 for(register int j = 0;j < m;++ j) 56 base[i][j] = a[i][j]; 57 for(;b;b >>= 1) 58 { 59 if(b & 1) 60 { 61 memset(tmp, 0, sizeof(tmp)); 62 for(register int i = 0;i < m;++ i) 63 for(register int j = 0;j < m;++ j) 64 for(register int q = 0;q < m;++ q) 65 { 66 tmp[i][j] += a[i][q] * base[q][j] % k; 67 if(tmp[i][j] >= k) tmp[i][j] -= k; 68 } 69 for(register int i = 0;i < m;++ i) 70 for(register int j = 0;j < m;++ j) 71 a[i][j] = tmp[i][j]; 72 } 73 memset(tmp, 0, sizeof(tmp)); 74 for(register int i = 0;i < m;++ i) 75 for(register int j = 0;j < m;++ j) 76 for(register int q = 0;q < m;++ q) 77 { 78 tmp[i][j] += base[i][q] * base[q][j] % k; 79 if(tmp[i][j] >= k) tmp[i][j] -= k; 80 } 81 for(register int i = 0;i < m;++ i) 82 for(register int j = 0;j < m;++ j) 83 base[i][j] = tmp[i][j]; 84 } 85 } 86 87 int main() 88 { 89 read(n), read(m), read(k);scanf("%s", s); 90 kmp(); 91 pow(n - 1); 92 int sum = 0; 93 for(register int i = 0;i < m;++ i) 94 { 95 sum += a[0][i]; 96 if(sum >= k) sum -= k; 97 } 98 printf("%d", sum); 99 return 0; 100 }