NTT/FFT与字符串匹配

字符串匹配问题,除了可以用KMPAC自动机等,有的还能利用NTT/FFT实现。
Link
本题中,对于每个在B中符合的位置i,都有j[0,m1],a[j]=b[j+i]a[j]=b[j+i]=
注意到,一般用加法实现,一般用乘法实现。
具体的,在本题中,我们定义F()=0,F(ch)=cha+1xy意为字符x可以与y匹配
那么xy=[F(x)F(y)(F(x)F(y))2=0](一个为0,则等式成立)
j[0,m1],F(aj)F(bj+i)(F(aj)F(bj+i))2=0
j=0m1F(aj)F(bj+i)(F(aj)F(bj+i))2=0
ai=ani1,有j=0m1F(anj1)F(bj+i)(F(anj1)F(bj+i))2=0
转化成卷积形式,依次拆开,有:resn+i1=p+q=n+i1ap3bq+p+q=n+i1apbq32p+q=n+i1ap2bq2=0
那么当resx=0时,输出x+2n+1是因为题目下标从1开始)

Code

#include <bits/stdc++.h>

using namespace std;

const int mod = 998244353, g = 3, G = (mod + 1) / 3;

int n, m, t, k, tot, out[300005], p[1200005], a0[1200005], b0[1200005], a[1200005], b[1200005], res[1200005];

char s1[300005], s2[300005];

int read()
{
	int x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
	return x;
}

int qpow(int base, int pw)
{
	int s = 1;
	while (pw)
	{
		if (pw & 1) s = 1ll * s * base % mod;
		base = 1ll * base * base % mod;
		pw >>= 1;
	}
	return s;
}

void g_l(int x)
{
	t = 1, k = 0;
	while (t <= x) t <<= 1, k ++ ;
	for (int i = 0; i < t; i ++ ) p[i] = (p[i >> 1] >> 1) | ((i & 1) << (k - 1));
	return;
}

void NTT(int *a, int o)
{
	for (int i = 0; i < t; i ++ ) if (i < p[i]) swap(a[i], a[p[i]]);
	for (int i = 1; i < t; i <<= 1)
	{
		int wn = qpow(o == 1 ? g : G, (mod - 1) / (i << 1));
		for (int j = 0; j < t; j += (i << 1))
		{
			int w = 1;
			for (int k = 0; k < i; k ++ , w = 1ll * w * wn % mod)
			{
				int p = a[j + k], q = 1ll * w * a[j + k + i] % mod;
				a[j + k] = (p + q) % mod, a[j + k + i] = (p - q + mod) % mod;
			}
		}
	}
	if (o == -1)
	{
		int div = qpow(t, mod - 2);
		for (int i = 0; i < t; i ++ ) a[i] = 1ll * a[i] * div % mod;
	}
	return;
}

int main()
{
	n = read(), m = read(), scanf("%s", s1), scanf("%s", s2);
	for (int i = 0; i < n; i ++ ) a0[i] = (s1[n - i - 1] == '*') ? 0 : s1[n - i - 1] - 'a' + 1;
	for (int i = 0; i < m; i ++ ) b0[i] = (s2[i] == '*') ? 0 : s2[i] - 'a' + 1;
	g_l(n + m);
	for (int i = 0; i < t; i ++ ) a[i] = 1ll * a0[i] * a0[i] % mod * a0[i] % mod, b[i] = b0[i];
	NTT(a, 1), NTT(b, 1);
	for (int i = 0; i < t; i ++ ) res[i] = (res[i] + 1ll * a[i] * b[i] % mod) % mod;
	for (int i = 0; i < t; i ++ ) a[i] = 1ll * a0[i] * a0[i] % mod, b[i] = 1ll * b0[i] * b0[i] % mod;
	NTT(a, 1), NTT(b, 1);
	for (int i = 0; i < t; i ++ ) res[i] = (res[i] - 2ll * a[i] * b[i] % mod + mod * 2ll) % mod;
	for (int i = 0; i < t; i ++ ) a[i] = a0[i], b[i] = 1ll * b0[i] * b0[i] % mod * b0[i] % mod;
	NTT(a, 1), NTT(b, 1);
	for (int i = 0; i < t; i ++ ) res[i] = (res[i] + 1ll * a[i] * b[i] % mod) % mod;
	NTT(res, -1);
	for (int i = n - 1; i <= m - 1; i ++ ) if (!res[i]) out[ ++ tot] = i + 2 - n;
	printf("%d\n", tot); for (int i = 1; i <= tot; i ++ ) printf("%d ", out[i]); putchar('\n');
	return 0;
}
posted @   andysj  阅读(124)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示