题意:
给你两个字符串S,T。
对于每个T长度的S子串,你需要求出他们的“距离”。
你每次可以将一个字符变成另一个字符,对于两个串都变,距离就是变化次数最小值使得两串相同。
字符集a - f。
题解:
如果长度相同,和CF另一题一模一样,只要把同一位置的两个字符连边,然后并查集一下就可以了。
现在还是一样,只是多了FFT,我们枚举转换字符i, j, 6 * 6 = 36种,然后把S中所有i字符变成1,其他的为0, T中所有j字符变成1,其他的为0。然后跑FFT,res[i]>0代表有这种边。
代码:
#include <bits/stdc++.h>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 3e5 + 5;
char s[MAXN], t[MAXN];
int par[MAXN][7];
int Find (int x, int i) {
return x == par[i][x] ? x : par[i][x] = Find (par[i][x], i);
}
int Union (int x, int y, int i) {
int xx = Find (x, i), yy = Find (y, i);
if (xx != yy) {
par[i][xx] = yy;
return 1;
}
return 0;
}
//typedef complex<double> CP;
struct CP {
double x, y;
CP() {}
CP (double x, double y) : x (x), y (y) {}
inline double real() {
return x;
}
inline CP operator * (const CP& r) const {
return CP (x * r.x - y * r.y, x * r.y + y * r.x);
}
inline CP operator - (const CP& r) const {
return CP (x - r.x, y - r.y);
}
inline CP operator + (const CP& r) const {
return CP (x + r.x, y + r.y);
}
inline CP conj (const CP &r) {
return CP (r.x, -r.y);
}
};
CP a[MAXN], b[MAXN];
int r[MAXN], res[MAXN];
void fft_init (int nm, int k) {
// Rader 操作
for (int i = 0; i < nm; ++i) r[i] = (r[i >> 1] >> 1) | ( (i & 1) << (k - 1) );
}
void fft (CP ax[], int nm, int op) {
for (int i = 0; i < nm; ++i) if (i < r[i]) swap (ax[i], ax[r[i]]);
for (int h = 2, m = 1; h <= nm; h <<= 1, m <<= 1) { // 枚举长度
CP wn = CP (cos (op * 2 * PI / h), sin (op * 2 * PI / h) );
for (int i = 0; i < nm; i += h) { // 枚举所有长度为 h 的区间
CP w (1, 0); // 旋转因子
for (int j = i; j < i + m; ++j, w = w * wn) { // 枚举角度
CP t = w * ax[j + m]; // 蝴蝶操作
ax[j + m] = ax[j] - t;
ax[j] = ax[j] + t;
}
}
}
if (op == -1) for (int i = 0; i < nm; ++i) ax[i].x /= nm;
}
void trans (int ax[], int bx[], int n, int m) {
int nm = 1, k = 0;
while (nm < 2 * n || nm < 2 * m) nm <<= 1, ++k;
for (int i = 0; i < n; ++i) a[i] = CP (ax[i], 0);
for (int i = 0; i < m; ++i) b[i] = CP (bx[i], 0);
for (int i = n; i < nm; ++i) a[i] = CP (0, 0);
for (int i = m; i < nm; ++i) b[i] = CP (0, 0);
fft_init (nm, k);
fft (a, nm, 1);
fft (b, nm, 1);
for (int i = 0; i < nm; ++i) a[i] = a[i] * b[i];
fft (a, nm, -1);
nm = n + m - 1;
for (int i = 0; i < nm; ++i) res[i] = (int) (a[i].real() + 0.5);
}
int ax[MAXN], bx[MAXN];
int ans[MAXN];
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
scanf ("%s %s", s + 1, t + 1);
int n = strlen (s + 1), m = strlen (t + 1);
reverse (t + 1, t + 1 + m);
for (int i = 1; i <= n; i++) for (int j = 0; j < 7; j++) par[i][j] = j;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
for (int k = 1; k <= n; k++) ax[k] = s[k] == i + 'a';
for (int k = 1; k <= m; k++) bx[k] = t[k] == j + 'a';
trans (ax, bx, n + 1, m + 1);
for (int k = m + 1; k <= n + 1; k++) if (res[k]) ans[k - m] += Union (i, j, k - m);
}
}
for (int i = 1; i <= n - m + 1; i++) printf ("%d ", ans[i]);
return 0;
}