版权声明:_ https://blog.csdn.net/lunch__/article/details/81949273
这个题目这个算法应该是卡过去的,
帮我改的时候还嘲讽我写
了..
其实只是常数写大了点…
首先不考虑数据范围,考虑巧妙一点的暴力,每次枚举两个串匹配,对应的字符在并查集中连边,最后的答案就是并查集中的边数,但是枚举串匹配的复杂度是 的
我们可以考虑用 优化匹配,由于字符集很小暴力枚举匹配是 的
对于每种子串匹配情况我们可以开一个并查集,每次把匹配到的字符设为 ,其他的设为 ,做一遍 来检查匹配,最后复杂度就是 ,差不多刚刚可以卡过去,注意复数类手写,一开始偷懒就卡 了
#include<bits/stdc++.h>
#define num(x) (x - 'a' + 1)
using namespace std;
typedef long double db;
const int N = 5e5 + 10;
const db Pi = acos(-1);
struct Complex {
db x, y;
Complex(db xx = 0, db yy = 0) {
x = xx, y = yy;
}
Complex operator + (const Complex &T) {
return Complex(x + T.x, y + T.y);
}
Complex operator - (const Complex &T) {
return Complex(x - T.x, y - T.y);
}
Complex operator * (const Complex &T) {
return Complex(x * T.x - y * T.y, x * T.y + y * T.x);
}
};
char S[N], T[N];
int n, m, rev[N], ans[N];
Complex a[N], b[N];
struct Union_Set {
int fa[7];
void Clear() {
for(int i = 1; i <= 6; ++ i)
fa[i] = i;
}
int Find(int x) {
return fa[x] = x == fa[x] ? x : Find(fa[x]);
}
bool Merge(int x, int y) {
x = Find(x), y = Find(y);
if(x == y) return false;
fa[x] = y; return true;
}
}Tr[N];
void FFT(int n, Complex *a, int fh) {
for(int i = 0; i < n; ++ i) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int limit = 2; limit <= n; limit <<= 1) {
db theta = 2.0 * Pi / limit;
Complex Wn = Complex{cos(theta), sin(theta) * fh}, W = Complex{1, 0};
for(int j = 0; j < n; j += limit, W = Complex{1, 0})
for(int i = j; i < j + (limit >> 1); ++ i, W = W * Wn) {
Complex a1 = a[i], a2 = a[i + (limit >> 1)] * W;
a[i] = a1 + a2, a[i + (limit >> 1)] = a1 - a2;
}
}
if(fh == -1)
for(int i = 0; i < n; ++ i)
a[i].x = a[i].x / n;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("CF954I.in", "r", stdin);
freopen("CF954I.out", "w", stdout);
#endif
int limit = 1, k = 0;
scanf("%s%s", S, T);
n = strlen(S), m = strlen(T);
while(limit <= (n + m - 2)) limit <<= 1, ++ k;
for(int i = 0; i < limit; ++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
for(int i = 0; i <= n - m; ++ i) Tr[i].Clear();
for(int Char1 = 1; Char1 <= 6; ++ Char1)
for(int Char2 = 1; Char2 <= 6; ++ Char2) {
if(Char1 == Char2) continue;
// printf("%c %c\n", Char1 + 'a' - 1, Char2 + 'a' - 1);
for(int i = 0; i < n; ++ i) a[i] = num(S[i]) == Char1;
for(int i = 0; i < m; ++ i) b[i] = num(T[i]) == Char2;
// for(int i = 0; i < n; ++ i) printf("%d ", int(a[i].real())); puts("");
reverse(b, b + m);
// for(int i = 0; i < m; ++ i) printf("%d ", int(b[i].real())); puts("");
FFT(limit, a, 1), FFT(limit, b, 1);
for(int i = 0; i < limit; ++ i) a[i] = a[i] * b[i];
FFT(limit, a, -1);
// for(int i = 0; i < limit; ++ i) printf("%d ", int(a[i].real())); puts("");
for(int i = 0; i <= n - m; ++ i)
if(a[m - 1 + i].x >= 0.5)
ans[i] += Tr[i].Merge(Char1, Char2);
for(int i = 0; i < limit; ++ i) a[i] = b[i] = 0;
}
for(int i = 0; i <= n - m; ++ i) printf("%d ", ans[i]);
//cerr << 1.0 * clock() / CLOCKS_PER_SEC << endl;
return 0;
}