我這麼菜怎麼可能會標算的神仙解法?
我們發現如果直接考慮有一個子串<S的話,是很有難度的。
不妨轉換爲沒有子串<S,也就是把T丟到S的KMP自動機 上,一直跑,注意只能走合法邊。
合法的意思是假設現在匹配了S[1…x],新加一個字符c,不存在
那這個東西怎麼計數呢?
如果已經有無限個T拼起來,再加一個T,在自動機上的點不會變。
也就是從自動機上一個點出發,走完T之後,回到原點的方案數。
那麼只需要枚舉起點,就可以得到一個的做法。
再想想有什麼美妙的性質,一個點的合法出邊中,只有至多一條不是轉移到0的,這個結論可以由合法邊的判定得到。
那麼枚舉這個點走了多少步走到0,後面的事情只用對0做一個預處理的dp。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 2005;
int m, n;
char s[N];
int nt[N], to[N][26];
const int mo = 998244353;
ll f[N][N], ans;
int main() {
freopen("repeat.in", "r", stdin);
freopen("repeat.out", "w", stdout);
scanf("%d", &m);
scanf("%s", s + 1); n = strlen(s + 1);
fo(i, 1, n) s[i] -= 'a';
int x = 0;
fo(i, 2, n) {
while(x && s[x + 1] != s[i]) x = nt[x];
x += s[x + 1] == s[i];
nt[i] = x;
}
fo(i, 0, n) {
fo(j, 0, 25) {
to[i][j] = -1; int ky = 1;
int x = i == n ? nt[i] : i;
while(x) ky &= s[x + 1] <= j, x = nt[x];
ky &= s[x + 1] <= j;
x = i == n ? nt[i] : i;
while(x && s[x + 1] != j) x = nt[x];
x += s[x + 1] == j;
if(ky) to[i][j] = x;
}
}
f[0][0] = 1;
fo(i, 0, m - 1) {
fo(j, 0, n) if(f[i][j]) {
fo(c, 0, 25) if(to[j][c] != -1) {
f[i + 1][to[j][c]] += f[i][j];
}
}
fo(j, 0, n) f[i + 1][j] %= mo;
}
ans = 1; fo(i, 1, m) ans = ans * 26 % mo;
fo(i, 0, n) {
int x = i;
fo(t, 0, m - 1) {
fo(c, 0, 25) if(to[x][c] == 0)
ans -= f[m - (t + 1)][i];
int y = -1;
fo(c, 0, 25) if(to[x][c] > 0)
y = to[x][c];
x = y;
if(y == -1) break;
}
if(x == i) ans --;
}
ans = (ans % mo + mo) % mo;
pp("%lld\n", ans);
}