【HNOI2008】【BZOJ1009】T考試
阿新 • • 發佈:2018-12-22
【題目連結】
【前置技能】
- DP
- 矩陣乘法
- AC自動機
- KMP
【題解】
- 預處理出每一位後面填~可以走到哪一位,DP狀態:表示現在是第位數字,匹配到第位。轉移比較顯然,不多贅述。因為比較大,所以要用矩陣乘法優化轉移。這裡覺得AC自動機寫起來比較方便,所以程式碼給出的是AC自動機的寫法。
- 時間複雜度
【程式碼】
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define LL long long #define MAXN 22 #define MAXLOG 30 using namespace std; int n, m, ans, mod; char s[MAXN]; int mat[MAXLOG + 1][MAXN][MAXN], f[1][MAXN], tmp[1][MAXN]; template <typename T> void chkmin(T &x, T y){x = min(x, y);} template <typename T> void chkmax(T &x, T y){x = max(x, y);} template <typename T> void read(T &x){ x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();} while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();} x *= f; } void update(int &x, int y){ x += y; if (x >= mod) x -= mod; } int mul(int x, int y){ return 1ll * x * y % mod; } struct AC_Automaton{ struct info{int son[10], fail, tag;}a[MAXN]; int cnt; void ins(char *s){ int len = strlen(s + 1); int pos = 0; for (int i = 1; i <= len; ++i){ int ch = s[i] - '0'; if (!a[pos].son[ch]) a[pos].son[ch] = ++cnt; pos = a[pos].son[ch]; } a[pos].tag = 1; } void build(){ static int q[MAXN], l = 0, r = -1; for (int ch = 0; ch < 10; ++ch) if (a[0].son[ch]) q[++r] = a[0].son[ch]; while (l <= r){ int pos = q[l++]; for (int ch = 0; ch < 10; ++ch) if (a[pos].son[ch]) { a[a[pos].son[ch]].fail = a[a[pos].fail].son[ch]; a[a[pos].son[ch]].tag |= a[a[a[pos].son[ch]].fail].tag; q[++r] = a[pos].son[ch]; } else a[pos].son[ch] = a[a[pos].fail].son[ch]; } } int go(int pos, int ch){ return a[pos].son[ch]; } void work(){ for (int pos = 0; pos <= cnt; ++pos){ if (a[pos].tag) continue; for (int ch = 0; ch < 10; ++ch){ int nxt = go(pos, ch); if (a[nxt].tag) continue; update(mat[0][pos][nxt], 1); } } for (int p = 1; p <= MAXLOG; ++p) for (int i = 0; i <= cnt; ++i) for (int j = 0; j <= cnt; ++j) for (int t = 0; t <= cnt; ++t) update(mat[p][i][j], mul(mat[p - 1][i][t], mat[p - 1][t][j])); f[0][0] = 1; for (int p = 1; p <= MAXLOG; ++p) if (n & (1 << p)) { memset(tmp, 0, sizeof(tmp)); for (int i = 0; i <= 0; ++i) for (int j = 0; j <= cnt; ++j) for (int t = 0; t <= cnt; ++t) update(tmp[i][j], mul(f[i][t], mat[p][t][j])); for (int i = 0; i <= 0; ++i) for (int j = 0; j <= cnt; ++j) f[i][j] = tmp[i][j]; } ans = 0; for (int pos = 0; pos <= cnt; ++pos) if (!a[pos].tag) update(ans, f[0][pos]); } }ACAM; int main(){ read(n), read(m), read(mod); scanf("%s", s + 1); ACAM.ins(s); ACAM.build(); ACAM.work(); printf("%d\n", ans); return 0; }