考慮到這個答案怎麼算。
能發現相當於是對應的字元間相連邊,那麼一個連通塊中的字元就要變成同一個字元。
於是一個連通塊的代價就是 \(sz - 1\)。
所以令有 \(x\) 個連通塊,最後的代價就是 \(|\Sigma| - x\)。
考慮到因為 \(|\Sigma| = 6\),而 \(B_6 = 203\)(貝爾數,\(B_n\) 意義為大小為 \(n\) 的劃分的數量)。
那麼就可以考慮暴力列舉每種劃分,也就是每種連通塊的情況。
那麼如果知道了連通塊的情況,那麼就可以把連通塊裡的所有字元都變為一個相同的字元。
那麼令變換完的字串為 \(S', T'\)。
那麼只要 \(S'_{l\sim r}\) 與 \(T'\) 能匹配上,\(S_{l\sim r}\) 的答案可能對應的就是當前劃分的情況,當然也有可能能讓劃分的集合更少,所以需要取個 \(\min\)。
對於匹配的部分用個 \(\text{KMP}\) 即可。
時間複雜度 \(O(B_{|\Sigma|}(|S| + |T|))\)。
程式碼
#include<bits/stdc++.h>
const int maxn = 2e5 + 10;
int n, m;
char S_[maxn], T_[maxn];
int S[maxn], T[maxn], s[maxn], t[maxn];
int to[6];
int nxt[maxn];
int ans[maxn];
inline void solve(int val) {
for (int i = 1; i <= n; i++)
s[i] = to[S[i]];
for (int i = 1; i <= n; i++)
t[i] = to[T[i]];
for (int i = 2, j = 0; i <= n; i++) {
while (j && t[j + 1] != t[i]) j = nxt[j];
j += t[j + 1] == t[i];
nxt[i] = j;
}
for (int i = 1, j = 0; i <= n; i++) {
while (j && t[j + 1] != s[i]) j = nxt[j];
j += t[j + 1] == s[i];
if (j == m) {
ans[i] = std::min(ans[i], val);
j = nxt[j];
}
}
}
void dfs(int w, std::vector<int> f) {
if (w == 6) {
solve(6 - f.size());
return ;
}
for (int p : f)
to[w] = p, dfs(w + 1, f);
to[w] = w, f.push_back(w), dfs(w + 1, f);
}
int main() {
scanf("%s%s", S_ + 1, T_ + 1);
n = strlen(S_ + 1), m = strlen(T_ + 1);
for (int i = 1; i <= n; i++)
S[i] = S_[i] - 'a';
for (int i = 1; i <= m; i++)
T[i] = T_[i] - 'a';
for (int i = m; i <= n; i++)
ans[i] = 1e9;
dfs(0, {});
for (int i = m; i <= n; i++)
printf("%d ", ans[i]);
return 0;
}