[Bzoj1009][HNOI2008]GT考试(动态规划)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1009
显而易见的动态规划加矩阵快速幂,不过转移方程不怎么好想,dp[i][j]表示长度为i的准考证号后j位与不吉利数字的前j位相同的方案数。则:
转移方程为$dp[i][j]=\sum_{k=0}^{m-1}dp[i-1][k]*g[k][j]$
答案为:$ans=\sum_{i=0}^{m}dp[n][i]$
g[i][j]表示长度为i的后缀变成长度为j的后缀的方案数。
而g数组可以用kmp预处理出来
附上洛谷40分不用矩阵优化的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 1 #include<bits/stdc++.h> 2 2 using namespace std; 3 3 typedef long long ll; 4 4 typedef unsigned long long ull; 5 5 const int maxn = 6e6 + 10; 6 6 ll Next[25]; 7 7 ll g[25][25]; 8 8 ll dp[maxn][25]; 9 9 char s[25]; 10 10 void getN(int n) { 11 11 Next[0] = -1; 12 12 int i = 0, j = -1; 13 13 while (i < n) { 14 14 if (j == -1 || s[i] == s[j]) 15 15 Next[++i] = ++j; 16 16 else 17 17 j = Next[j]; 18 18 } 19 19 } 20 20 int main() { 21 21 ll n, m, mod; 22 22 scanf("%lld%lld%lld", &n, &m, &mod); 23 23 scanf("%s", s); 24 24 getN(m); 25 25 Next[0] = 0; 26 26 for (int i = 0; i < m; i++) { 27 27 for (int j = '0'; j <= '9'; j++) { 28 28 int t = i; 29 29 while (t&& s[t] != j) 30 30 t = Next[t]; 31 31 if (s[t] == j) 32 32 t++; 33 33 g[i][t]++; 34 34 } 35 35 } 36 36 dp[0][0] = 1; 37 37 for (int i = 1; i <= n; i++) { 38 38 for (int j = 0; j < m; j++) { 39 39 for (int k = 0; k < m; k++) { 40 40 dp[i][j] = (dp[i][j] + dp[i - 1][k] * g[k][j]) % mod; 41 41 } 42 42 } 43 43 } 44 44 ll ans = 0; 45 45 for (int i = 0; i < m; i++) 46 46 ans = (ans + dp[n][i]) % mod; 47 47 printf("%lld\n", ans); 48 48 }
以及正解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned long long ull; 5 const int maxn = 6e6 + 10; 6 ll Next[25]; 7 ll n, m, mod; 8 ll dp[25][25]; 9 char s[25]; 10 void getN(int n) { 11 Next[0] = -1; 12 int i = 0, j = -1; 13 while (i < n) { 14 if (j == -1 || s[i] == s[j]) 15 Next[++i] = ++j; 16 else 17 j = Next[j]; 18 } 19 } 20 struct matrix { 21 ll cnt[25][25]; 22 matrix() { memset(cnt, 0, sizeof(cnt)); } 23 matrix operator *(const matrix a)const { 24 matrix ans; 25 for (int i = 0; i <= m; i++) { 26 for (int j = 0; j <= m; j++) { 27 ans.cnt[i][j] = 0; 28 for (int k = 0; k <= m; k++) 29 ans.cnt[i][j] = (ans.cnt[i][j] + cnt[i][k] * a.cnt[k][j]) % mod; 30 } 31 } 32 return ans; 33 } 34 }; 35 matrix powM(matrix a, int b) { 36 matrix ans = matrix(); 37 for (int i = 0; i <= m; i++) 38 ans.cnt[i][i] = 1; 39 while (b) { 40 if (b & 1) 41 ans = ans * a; 42 a = a * a; 43 b /= 2; 44 } 45 return ans; 46 } 47 int main() { 48 matrix g, ans, dp = matrix(); 49 scanf("%lld%lld%lld", &n, &m, &mod); 50 scanf("%s", s); 51 getN(m); 52 Next[0] = 0; 53 memset(g.cnt, 0, sizeof(g.cnt)); 54 for (int i = 0; i < m; i++) { 55 for (int j = '0'; j <= '9'; j++) { 56 int t = i; 57 while (t&& s[t] != j) 58 t = Next[t]; 59 if (s[t] == j) 60 t++; 61 g.cnt[i][t]++; 62 } 63 } 64 dp.cnt[0][0] = 1; 65 ans = powM(g, n); 66 ans = dp * ans; 67 ll sum = 0; 68 for (int i = 0; i < m; i++) 69 sum = (sum + ans.cnt[0][i]) % mod; 70 printf("%lld\n", sum); 71 }