洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)
題目鏈接:點(diǎn)擊查看
題目大意:給出一個(gè)長度為 nnn 的字符串 sss 和一個(gè)長度為 mmm 的字符串 ttt,都含有通配符 ‘*’,現(xiàn)在問字符串 ttt 可以匹配字符串 nnn 的哪些位置
題目分析:模糊匹配的模板題,這里只記錄一下公式,具體推導(dǎo)博客詳見:
https://www.luogu.com.cn/blog/Ebola-Emperor/solution-p4173
先放兩個(gè)公式:
設(shè)原模式串為 AAA,匹配串 BBB,AAA 的翻轉(zhuǎn) SSS
P(x)P(x)P(x) 為全匹配函數(shù),若 P(x)=0P(x)=0P(x)=0 則稱 BBB 以第 xxx 位結(jié)束的連續(xù) mmm 位,與 AAA 完全匹配
普通的單模式串匹配:P(x)=T+f(x)?f(x?m)?2g(x)P(x)=T+f(x)-f(x-m)-2g(x)P(x)=T+f(x)?f(x?m)?2g(x)
其中 T=∑i=0m?1S(i)2T=\sum\limits_{i=0}^{m-1}S(i)^2T=i=0∑m?1?S(i)2,f(x)=∑i=0xB(i)2f(x)=\sum\limits_{i=0}^{x}B(i)^2f(x)=i=0∑x?B(i)2,g(x)=∑i+j=xS(i)B(j)g(x)=\sum\limits_{i+j=x}S(i)B(j)g(x)=i+j=x∑?S(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=xS(i)3B(j)+∑i+j=xS(i)B(j)3?2∑i+j=xS(i)2B(j)2P(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)^2P(x)=i+j=x∑?S(i)3B(j)+i+j=x∑?S(i)B(j)3?2i+j=x∑?S(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實(shí)現(xiàn))
// 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(int i = 0; i < limit; i++) if(i < r[i]) swap(A[i], A[r[i]]);for(int mid = 1; mid < limit; mid <<= 1) { LL Wn = fastpow( type == 1 ? G : Gi , (mod - 1) / (mid << 1));for(int j = 0; j < limit; j += (mid << 1)) {LL w = 1;for(int k = 0; k < mid; k++, w = (w * Wn) % mod) {int x = A[j + k], y = w * A[j + k + mid] % mod;A[j + k] = (x + y) % mod,A[j + k + mid] = (x - y + mod) % mod;}}} } char s[N],t[N]; int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);read(m),read(n);while(limit<=n+m) limit<<=1,L++;for(int i=0;i<limit;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));scanf("%s%s",t,s);reverse(t,t+m);for(int i=0;i<n;i++) A[i]=(s[i]!='*')?(s[i]-'a'+1):0;for(int i=0;i<m;i++) B[i]=(t[i]!='*')?(t[i]-'a'+1):0;for(int i=0;i<limit;i++) a[i]=A[i]*A[i]*A[i],b[i]=B[i];NTT(a,1);NTT(b,1);for(int i=0;i<limit;i++) P[i]=(P[i]+a[i]*b[i])%mod;for(int i=0;i<limit;i++) a[i]=A[i],b[i]=B[i]*B[i]*B[i];NTT(a,1);NTT(b,1);for(int i=0;i<limit;i++) P[i]=(P[i]+a[i]*b[i])%mod;for(int i=0;i<limit;i++) a[i]=A[i]*A[i],b[i]=B[i]*B[i];NTT(a,1);NTT(b,1);for(int i=0;i<limit;i++) P[i]=(P[i]-(2*a[i]*b[i])%mod+mod)%mod;NTT(P,-1);vector<int>ans;for(int i=m-1;i<n;i++) {if(!P[i]) {ans.push_back(i-m+2);}}cout<<ans.size()<<endl;for(auto it:ans) {printf("%d ",it);}return 0; }總結(jié)
以上是生活随笔為你收集整理的洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分数Frac类
- 下一篇: HDU多校3 - 6975 Forgiv