题解 [CF954I] Yet Another String Matching Problem
- CF954I Yet Another String Matching Problem
题目描述
给定两个字符串
每次操作可以将一种字符变成另外一种字符,对于
正解
可以暴力枚举集合划分(即哪些字符要变成相同的),然后用哈希或者 KMP 做到
之前有些题解说的复杂度不太对,集合划分的复杂度是
讲一下怎么搜集合划分吧。
其实集合划分的写法就跟生成森林的方法差不多。
从小往大枚举元素,对于一个元素,它有两种操作 :
-
作为新的森林的根。
-
加入一个已经存在的森林。
给出代码 :
int fa[N];
int blk[N], cb;
void divSet(int dep) {
if(dep > maxDep) {
solve();
return void();
}
fa[dep] = dep;
blk[++cb] = dep;
divSet(dep + 1);
blk[cb--] = 0;
for(int i = 1; i <= cb; ++i) {
fa[dep] = blk[i];
divSet(dep + 1);
}
}
话说这题
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 125005;
int ans[N];
int fail[N];
int lenS, lenT;
char s[N], t[N];
int fa[N];
int blk[N], cb;
inline int tr(char ch) { return ch - 'a'; }
void solve(int res) {
int cur(0);
fail[1] = 0;
for(int i = 2; i <= lenT; ++i) {
while(cur && fa[tr(t[i])] != fa[tr(t[cur + 1])])
cur = fail[cur];
if(fa[tr(t[i])] == fa[tr(t[cur + 1])])
++cur;
fail[i] = cur;
}
cur = 0;
for(int i = 1; i <= lenS; ++i) {
while(cur && fa[tr(s[i])] != fa[tr(t[cur + 1])])
cur = fail[cur];
if(fa[tr(s[i])] == fa[tr(t[cur + 1])])
++cur;
if(cur == lenT) {
ans[i] = min(ans[i], res);
cur = fail[cur];
}
}
}
void divSet(int dep) {
if(dep > tr('f')) {
++cnt;
solve(6 - cb);
return void();
}
fa[dep] = dep;
blk[++cb] = dep;
divSet(dep + 1);
blk[cb--] = 0;
for(int i = 1; i <= cb; ++i) {
fa[dep] = blk[i];
divSet(dep + 1);
}
}
int main() {
scanf("%s %s", s + 1, t + 1);
lenS = strlen(s + 1);
lenT = strlen(t + 1);
for(int i =lenT; i <= lenS; ++i)
ans[i] = 233;
divSet(0);
for(int i = lenT; i <= lenS; ++i)
printf("%d%c", ans[i], " \n"[i == lenS]);
return 0;
}