洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的字符串 s s s 和一个长度为 m m m 的字符串 t t t,都含有通配符 ‘*’,现在问字符串 t t t 可以匹配字符串 n n n 的哪些位置

题目分析:模糊匹配的模板题,这里只记录一下公式,具体推导博客详见:
https://www.luogu.com.cn/blog/Ebola-Emperor/solution-p4173

先放两个公式:

设原模式串为 A A A,匹配串 B B B A A A 的翻转 S S S

P ( x ) P(x) P(x) 为全匹配函数,若 P ( x ) = 0 P(x)=0 P(x)=0 则称 B B B 以第 x x x 位结束的连续 m m m 位,与 A A A 完全匹配


普通的单模式串匹配 P ( x ) = T + f ( x ) − f ( x − m ) − 2 g ( x ) P(x)=T+f(x)-f(x-m)-2g(x) P(x)=T+f(x)f(xm)2g(x)

其中 T = ∑ i = 0 m − 1 S ( i ) 2 T=\\sum\\limits_{i=0}^{m-1}S(i)^2 T=i=0m1S(i)2 f ( x ) = ∑ i = 0 x B ( i ) 2 f(x)=\\sum\\limits_{i=0}^{x}B(i)^2 f(x)=i=0xB(i)2 g ( x ) = ∑ i + j = x S ( i ) B ( j ) g(x)=\\sum\\limits_{i+j=x}S(i)B(j) g(x)=i+j=xS(i)B(j)

伪代码:

void FFT_Match(char *s1,char *s2,int m,int n)
{
	for(int i=0;i<m;i++) A[i].r=s1[i]-'a'+1;
	for(int i=0;i<n;i++) B[i].r=s2[i]-'a'+1;
	reverse(A,A+m);double T=0;
	for(int i=0;i<m;i++) T+=A[i].r*A[i].r;
	f[0]=B[0].r*B[0].r;
	for(int i=1;i<n;i++) f[i]=f[i-1]+B[i].r*B[i].r;
	FFT(A,len,1);FFT(B,len,1);
	for(int i=0;i<len;i++) g[i]=A[i]*B[i];
	FFT(g,len,-1);
	for(int x=m-1;x<n;x++)
	{
		double P=T+f[x]-f[x-m]-2*g[x].r;
		if(fabs(P)<eps) printf("%d ",x-m+2);
	}
}

带通配符的单模式串匹配 P ( x ) = ∑ i + j = x S ( i ) 3 B ( j ) + ∑ i + j = x S ( i ) B ( j ) 3 − 2 ∑ i + j = x S ( i ) 2 B ( j ) 2 P(x)=\\sum\\limits_{i+j=x}S(i)^3B(j)+\\sum\\limits_{i+j=x}S(i)B(j)^3-2\\sum\\limits_{i+j=x}S(i)^2B(j)^2 P(x)=i+j=xS(i)3B(j)+i+j=xS(i)B(j)32i+j=xS(i)2B(j)2

伪代码:

void FFT_match(char *s1,char *s2,int m,int n)
{
	reverse(ss1,ss1+m);
	for(int i=0;i<m;i++) A[i]=(s1[i]!='*')?(s1[i]-'a'+1):0;
	for(int i=0;i<n;i++) B[i]=(s2[i]!='*')?(s2[i]-'a'+1):0;
	
	for(int i=0;i<len;i++) a[i]=Comp(A[i]*A[i]*A[i],0),b[i]=Comp(B[i],0);
	FFT(a,len,1);FFT(b,len,1);
	for(int i=0;i<len;i++) P[i]=P[i]+a[i]*b[i];
	
	for(int i=0;i<len;i++) a[i]=Comp(A[i],0),b[i]=Comp(B[i]*B[i]*B[i],0);
	FFT(a,len,1);FFT(b,len,1);
	for(int i=0;i<len;i++) P[i]=P[i]+a[i]*b[i];
	
	for(int i=0;i<len;i++) a[i]=Comp(A[i]*A[i],0),b[i]=Comp(B[i]*B[i],0);
	FFT(a,len,1);FFT(b,len,1);
	for(int i=0;i<len;i++) P[i]=P[i]-a[i]*b[i]*Comp(2,0);
	
	FFT(P,len,-1);
	for(int i=m-1;i<n;i++) if(fabs(P[i].r)<=1e-7) printf("%d ",i-m+2);
}

本题代码:(NTT实现)

// Problem: P4173 残缺的字符串
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4173
// Memory Limit: 128 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
const int mod=998244353,G=3,Gi=332748118; 
int n,m,limit = 1,L,r[N<<2],res[N<<2];
LL a[N<<2],b[N<<2],P[N<<2],A[N<<2],B[N<<2];
inline LL fastpow(LL a, LL k) {
	LL base = 1;
	while(k) {
		if(k & 1) base = (base * a ) % mod;
		a = (a * a) % mod;
		k >>= 1;
	}
	return base % mod;
}
inline void NTT(LL *A, int type) {
	for(

以上是关于洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)的主要内容,如果未能解决你的问题,请参考以下文章

P4173 残缺的字符串 fft

P4173 残缺的字符串(FFT)

P4173 残缺的字符串

P4173 残缺的字符串

luogu P4173 残缺的字符串 FFT

[Luogu P4173]残缺的字符串 ( 数论 FFT)