http://www.lydsy.com/JudgeOnline/problem.php?id=1009
设dp[i][j]表示确定了前i位,最后j位是所给串的前缀的方案数。
设A[i][j]表示从i这个前缀到j这个前缀的方案数。
那么有dp[i][j] = ∑(dp[i][k] * A[k][j])。
A[][]可以用KMP搞出来,然后线性递推用矩阵快速幂搞一搞就行了。
无限仰视菊苣YZX的AC自动机写法。
/*Footprints In The Blood Soaked Snow */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 25; int n, m, p, s[maxn], fail[maxn]; struct _mat { int num[maxn][maxn]; } E, trans; inline int iread() { int f = 1, x = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return f * x; } inline _mat mul(_mat &A, _mat &B) { _mat C; for(int i = 0; i < m; i++) for(int j = 0; j < m; j++) { C.num[i][j] = 0; for(int k = 0; k < m; k++) C.num[i][j] = (C.num[i][j] + A.num[i][k] * B.num[k][j]) % p; } return C; } inline _mat qpow(_mat &A, int n) { _mat ans = E; for(_mat t = A; n; n >>= 1, t = mul(t, t)) if(n & 1) ans = mul(ans, t); return ans; } char str[maxn]; int main() { n = iread(); m = iread(); p = iread(); scanf("%s", str + 1); for(int i = 1; i <= m; i++) s[i] = str[i] - '0'; for(int i = 2, j = 0; i <= m; fail[i++] = j) { for(; j != 0 && s[j + 1] != s[i]; j = fail[j]); if(s[j + 1] == s[i]) j++; } for(int i = 0; i < m; i++) for(int j = 0; j <= 9; j++) { int k = i; for(; k != 0 && s[k + 1] != j; k = fail[k]); if(s[k + 1] == j) k++; trans.num[i][k] = (trans.num[i][k] + 1) % p; } for(int i = 0; i < m; i++) E.num[i][i] = 1; _mat res = qpow(trans, n); int ans = 0; for(int i = 0; i < m; i++) ans = (ans + res.num[0][i]) % p; printf("%d\n", ans); return 0; }