Codeforces 954I Yet Another String Matching Problem

rizynvu發表於2024-04-20

考慮到這個答案怎麼算。
能發現相當於是對應的字元間相連邊,那麼一個連通塊中的字元就要變成同一個字元。
於是一個連通塊的代價就是 \(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;
}

相關文章