生活随笔
收集整理的這篇文章主要介紹了
P4173 残缺的字符串 FFT匹配含有通配符的字符串
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
給你兩個長度為m,nm,nm,n的串a,ba,ba,b,問你bbb串中每個長度為mmm的連續字串能否與aaa完全匹配,其中含有通配符?*?,輸出每個位置的開頭。
n,m≤3e5n,m\le3e5n,m≤3e5
思路:
比較容易想到魔改kmpkmpkmp,但是你會發現怎么改都aaa不掉這個題。
先不考慮通配符,定義c(x,y)c(x,y)c(x,y)表示ax?bya_x-b_yax??by?,顯然c(x,y)=0c(x,y)=0c(x,y)=0時代表axa_xax?與byb_yby?這個位置匹配。
定義函數f(x)=∑i=0m?1C(i,x?m+i+1)f(x)=\sum_{i=0}^{m-1}C(i,x-m+i+1)f(x)=∑i=0m?1?C(i,x?m+i+1),我們發現不能根據f(x)f(x)f(x)是否為000來判斷是否匹配,因為有ab,baab,baab,ba這種串。不難發現問題就是出現了負數,我們考慮將其加個絕對值?絕對值不是很好處理,所以考慮給他加一個平方,即f(x)=∑i=0m?1(A(i)?B(x?m+i+1))2f(x)=\sum_{i=0}^{m-1}(A(i)-B(x-m+i+1))^2f(x)=∑i=0m?1?(A(i)?B(x?m+i+1))2,這個獅子已經很像FFTFFTFFT了,考慮將其展開,f(x)=∑i=0m?1A(i)2+∑i=0m?1B(x?m+i+1)2?2?∑i=0m?1A(i)?B(x?m+i+1)f(x)=\sum_{i=0}^{m-1}A(i)^2+\sum_{i=0}^{m-1}B(x-m+i+1)^2-2*\sum_{i=0}^{m-1}A(i)*B(x-m+i+1)f(x)=∑i=0m?1?A(i)2+∑i=0m?1?B(x?m+i+1)2?2?∑i=0m?1?A(i)?B(x?m+i+1),前面兩項很好處理,只有最后這一項不是很好看,考慮將AAA串翻轉一下,即∑i=0m?1A(m?i?1)?B(x?m+i+1)\sum_{i=0}^{m-1}A(m-i-1)*B(x-m+i+1)∑i=0m?1?A(m?i?1)?B(x?m+i+1),觀察一下,這不就是個卷積!即g(x)=∑i+j=xA(i)?B(j)g(x)=\sum_{i+j=x}A(i)*B(j)g(x)=∑i+j=x?A(i)?B(j),所以卷一下就好啦。
有通配符怎么辦呢?
按照上面的思路,我們是將相等的數變成了000,所以我們只需要改一下C(x,y)C(x,y)C(x,y)的定義,改為C(x,y)=(Ax?By)2AxByC(x,y)=(A_x-B_y)^2A_xB_yC(x,y)=(Ax??By?)2Ax?By?,即當某個位置是通配符的時候,將這個位置的A,BA,BA,B都賦值為000即可。
推導方法與上面相同,這里直接給出答案:f(x)=∑i+j=xA(x)3B(x)+∑i+j=xA(x)B(x)3?2?∑i+j=xA(x)2B(x)2f(x)=\sum_{i+j=x}A(x)^3B(x)+\sum_{i+j=x}A(x)B(x)^3-2*\sum_{i+j=x}A(x)^2B(x)^2f(x)=i+j=x∑?A(x)3B(x)+i+j=x∑?A(x)B(x)3?2?i+j=x∑?A(x)2B(x)2
做666次即可。
小優化:由于最終只用到了前nnn項,所以卷的長度定義為>=n>=n>=n的最小222的冪次即可。
不加這個優化很可能過不了,需要換NTTNTTNTT。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=6000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6,PI
=acos(-1);int n
,m
;
int rev
[N
];
int bit
,limit
;
int A
[N
],B
[N
];
char s1
[N
],s2
[N
];
double p1
[N
],p2
[N
];struct Complex {double x
,y
;Complex
operator + (const Complex
& t
) const { return {x
+t
.x
,y
+t
.y
}; }Complex
operator - (const Complex
& t
) const { return {x
-t
.x
,y
-t
.y
}; }Complex
operator * (const Complex
& t
) const { return {x
*t
.x
-y
*t
.y
,x
*t
.y
+y
*t
.x
}; }
}a
[N
],b
[N
],c
[N
],d
[N
],ans
[N
];void fft(Complex a
[],int inv
) {for(int i
=0;i
<limit
;i
++) if(i
<rev
[i
]) swap(a
[i
],a
[rev
[i
]]);for(int mid
=1;mid
<limit
;mid
<<=1) {Complex w1
=Complex({p1
[mid
],inv
*p2
[mid
]});for(int i
=0;i
<limit
;i
+=mid
*2) {Complex wk
=Complex({1,0});for(int j
=0;j
<mid
;j
++,wk
=wk
*w1
) {Complex x
=a
[i
+j
],y
=wk
*a
[i
+j
+mid
];a
[i
+j
]=x
+y
; a
[i
+j
+mid
]=x
-y
;}}}
}int main()
{
cin
>>m
>>n
>>s1
>>s2
;for(int i
=0;i
<m
;i
++) A
[i
]=s1
[i
]=='*'? 0:s1
[i
]-'a'+1;for(int i
=0;i
<n
;i
++) B
[i
]=s2
[i
]=='*'? 0:s2
[i
]-'a'+1;reverse(A
,A
+m
);while((1<<bit
)<=n
) bit
++;limit
=1<<bit
;for(int i
=0;i
<limit
;i
++) rev
[i
]=(rev
[i
>>1]>>1)|((i
&1)<<(bit
-1));for(int mid
=1;mid
<limit
;mid
<<=1) p1
[mid
]=cos(PI
/mid
),p2
[mid
]=sin(PI
/mid
);for(int i
=0;i
<m
;i
++) a
[i
]={1.0*A
[i
]*A
[i
]*A
[i
],0},c
[i
]={1.0*A
[i
]*A
[i
],0};for(int i
=0;i
<n
;i
++) b
[i
]={1.0*B
[i
],0},d
[i
]={1.0*B
[i
]*B
[i
],0};fft(a
,1); fft(b
,1); fft(c
,1); fft(d
,1);Complex now
={2,0};for(int i
=0;i
<limit
;i
++) ans
[i
]=ans
[i
]+a
[i
]*b
[i
]-c
[i
]*d
[i
]*now
;for(int i
=0;i
<limit
;i
++) a
[i
]=b
[i
]={0,0};for(int i
=0;i
<m
;i
++) a
[i
]={1.0*A
[i
],0};for(int i
=0;i
<n
;i
++) b
[i
]={1.0*B
[i
]*B
[i
]*B
[i
],0};fft(a
,1); fft(b
,1); for(int i
=0;i
<limit
;i
++) ans
[i
]=ans
[i
]+a
[i
]*b
[i
];fft(ans
,-1);vector
<int>v
;for(int i
=m
-1;i
<n
;i
++) if((fabs(ans
[i
].x
/limit
))<0.5) v
.pb(i
-m
+2);printf("%d\n",v
.size());for(auto x
:v
) printf("%d ",x
);return 0;
}
總結
以上是生活随笔為你收集整理的P4173 残缺的字符串 FFT匹配含有通配符的字符串的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。