[HNOI2008] GT考试
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1009
[算法]
首先用kmp预处理最长的后缀 = 前缀
然后 , 用Fi,j表示前i位 , 匹配j位的方案数
矩阵优化即可
时间复杂度 : O(M ^ 3logN)
[代码]
#include<bits/stdc++.h> using namespace std; const int N = 25; int n , m , P; int nxt[N]; int a[N][N] , b[N][N]; char s[N]; template <typename T> inline void update(T &x , T y) { x += y; x %= P; } inline void multipy(int a[N][N] , int b[N][N]) { static int ret[N][N]; memset(ret , 0 , sizeof(ret)); for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { for (int k = 0; k < m; k++) { ret[i][j] = (ret[i][j] + 1LL * a[i][k] * b[k][j] % P) % P; } } } for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { a[i][j] = ret[i][j]; } } } int main() { scanf("%d%d%d" , &n , &m , &P); scanf("%s" , s + 1); nxt[1] = 0; for (int i = 2; i <= m; i++) { int tmp = nxt[i - 1]; while (tmp > 0 && s[tmp + 1] != s[i]) tmp = nxt[tmp]; if (s[tmp + 1] == s[i]) ++tmp; nxt[i] = tmp; } for (int i = 0; i < m; i++) { for (int j = 0; j <= 9; j++) { int tmp = i; while (tmp > 0 && s[tmp + 1] - '0' != j) tmp = nxt[tmp]; if (s[tmp + 1] - '0' == j) ++tmp; if (tmp != m) update(b[tmp][i] , 1); } } for (int i = 0; i < m; i++) a[i][i] = 1; while (n > 0) { if (n & 1) multipy(a , b); multipy(b , b); n >>= 1; } int ans = 0; for (int i = 0; i < m; i++) update(ans , a[i][0]); printf("%d\n" , ans); return 0; }