Bzoj1009: [HNOI2008]GT考試
阿新 • • 發佈:2018-01-19
mes amp down int print char tin bzoj noi2008
題面
傳送門
Sol
設\(f[i][j]\)表示到第\(i\)個數,最後\(j\)個為不吉利數字的前綴的方案數
於是就可以寫一個\(KMP\)套暴力\(DP\)跳\(next\)轉移
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; IL ll Read(){ RG ll x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, m, k, f[101010][30], nxt[30], ans; char s[30]; int main(RG int argc, RG char* argv[]){ n = Read(); m = Read(); k = Read(); scanf(" %s", s + 1); for(RG int i = 2, j = 0; i <= m; ++i){ while(j && s[i] != s[j + 1]) j = nxt[j]; if(s[i] == s[j + 1]) nxt[i] = ++j; } f[0][0] = 1; for(RG int i = 1; i <= n; ++i) for(RG int j = 0; j < m; ++j){ if(!f[i - 1][j]) continue; for(RG int l = '0'; l <= '9'; ++l){ RG int p = j; while(p && l != s[p + 1]) p = nxt[p]; if(s[p + 1] == l) ++p; f[i][p] = (f[i][p] + f[i - 1][j] % k) % k; } } for(RG int i = 0; i < m; ++i) ans = (ans + f[n][i]) % k; printf("%d\n", ans); return 0; }
我們發現轉移是一樣的,預處理出來,\(n\)這麽大那就矩陣乘法優化一下
# include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; IL ll Read(){ RG ll x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, m, k, nxt[30], ans; char s[30]; struct Matrix{ int a[30][30]; IL void Clear(){ Fill(a, 0); } IL void Init(){ Clear(); for(RG int i = 0; i < m; ++i) a[i][i] = 1; } IL int* operator [](RG int x){ return a[x]; } IL Matrix operator *(RG Matrix B){ RG Matrix C; C.Clear(); for(RG int i = 0; i < m; ++i) for(RG int j = 0; j < m; ++j) for(RG int l = 0; l < m; ++l) (C[i][l] += (1LL * a[i][j] * B[j][l] % k)) %= k; return C; } } S, E; int main(RG int argc, RG char* argv[]){ n = Read(); m = Read(); k = Read(); scanf(" %s", s + 1); for(RG int i = 2, j = 0; i <= m; ++i){ while(j && s[i] != s[j + 1]) j = nxt[j]; if(s[i] == s[j + 1]) nxt[i] = ++j; } for(RG int i = 0; i < m; ++i) for(RG int j = '0'; j <= '9'; ++j){ RG int p = i; while(p && j != s[p + 1]) p = nxt[p]; if(s[p + 1] == j) ++p; ++E[i][p]; } S[0][0] = 1; for(RG int i = n; i; i >>= 1, E = E * E) if(i & 1) S = S * E; for(RG int i = 0; i < m; ++i) ans = (ans + S[0][i]) % k; printf("%d\n", ans); return 0; }
Bzoj1009: [HNOI2008]GT考試