Awesome Brother Gym - 102020A (kmp优化dp)
kmp优化dp
https://vjudge.net/problem/Gym-102020A
vector<int> v[10];
char M[111];
int n, m, k;
ll dp[10010][101][10];
int kmp[10010];
int pre[10010][12];
int nxt[10010];
void get_next(char* s, int* next) {
int len = strlen(s);
int k = next[0] = -1;
for (int i = 0; i < len; ) {
if (k == -1 || s[i] == s[k]) {
next[++i] = ++k;
}
else
k = next[k];
}
}
int failureFunction(char* p) {
int len = strlen(p), cnt = 0;
strcat(p, "#");
int now = kmp[0] = -1;
for (int i = 0; i < 10; ++i) pre[0][i] = -1;
for (int i = 1; p[i]; ++i) {
for (int j = 0; j < 10; ++j) {
int tmp = now;
char ch = j + '0';
while (tmp != -1 && p[tmp + 1] != ch) tmp = kmp[tmp];
if (ch == p[tmp + 1]) pre[i][j] = ++tmp;
else pre[i][j] = tmp = -1;
}
while (now != -1 && p[now + 1] != p[i]) now = kmp[now];
if (p[now + 1] == p[i]) kmp[i] = ++now;
else kmp[i] = now = -1;
if (now == len - 1) cnt++;
}
return cnt;
}
ll solve(int pos, int match, int now) {
if (m and match == m) return 0;
if (pos == n) return 1ll;
ll& res = dp[pos][match][now];
if (~res) return res;
res = 0;
for (auto& x : v[now]) {
char nxt = x + '0';
if (nxt == M[match]) res += solve(pos + 1, match + 1, x);
else if (match == 0) res += solve(pos + 1, 0, x);
else res += solve(pos + 1, pre[match][x] + 1, x);
res %= mod;
}
return res;
}
signed main() {
v[0] = { 4, 6 };
v[1] = { 6, 8 };
v[2] = { 7, 9 };
v[3] = { 4, 8 };
v[4] = { 0, 3, 9 };
v[5] = {};
v[6] = { 0, 1, 7 };
v[7] = { 2, 6 };
v[8] = { 1, 3 };
v[9] = { 2, 4 };
memset(dp, -1, sizeof dp);
scanf("%lld %lld %lld", &n, &m, &k);
if (m) scanf("%s", M);
else M[0] = '\0';
failureFunction(M);
printf("%lld\n", solve(0, 0, k));
return 0;
}