题意:给你两个字符串AB,求B在A中选一个起点开始匹配,能匹配到的位置(对应位置的RPS比大小,胜利的位置)的最大数量。
R:石头 P:布 S:剪刀
第一次知道FFT可以有这样的妙用,可以用于字符串匹配,求最大匹配数,这道题需要变一变;
FFT内部实现数学原理至今不懂,只知道是用于多项式乘法,优化成O(n * log(n))的复杂度,只是把FFT当成模板来使用。
首先处理一下两个字符串,将s1字符串内的R变为P,P变为S,S变为R,将s2字符串翻转;
之后对每个字符进行FFT,将s1字符串变为01串,s2字符串也变成01串,不是该字符的都是0;
为什么翻转呢?
因为多项式乘法最后答案是C(k) = a(0) * b(k) + a(1) * b(k - 1)+ …,因为字符串是正向匹配的,如果将匹配串翻转一下,会因为多项式的性质变为正向匹配,如果b串翻转一下,就变成了C(k) = a(0) * b(0) +…
因为匹配串的长度为m,所以最后取(m - 1)~ (n + m - 1)位置上的数即可,因为m - 2就不是从头开始匹配了。
这个方法太巧太妙了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 5;
// 这一大坨fft的代码实现不要动的
const double PI = acos(-1.0);
struct Complex {
double x, y;
Complex(double _x = 0.0, double _y = 0.0) {
x = _x;
y = _y;
}
Complex operator - (const Complex &b)const {
return Complex(x-b.x, y-b.y);
}
Complex operator + (const Complex &b)const {
return Complex(x+b.x, y+b.y);
}
Complex operator * (const Complex &b)const {
return Complex(x*b.x-y*b.y, x*b.y+y*b.x);
}
};
void change(Complex y[], int len) {
int i, j, k;
for(i = 1, j = len/2; i < len-1; i++) {
if (i < j) swap(y[i], y[j]);
k = len/2;
while(j >= k) {
j -= k;
k /= 2;
}
if (j < k) j += k;
}
}
void fft(Complex y[], int len, int on) {
change(y, len);
for(int h = 2; h <= len; h <<= 1) {
Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
for(int j = 0; j < len; j += h) {
Complex w(1, 0);
for(int k = j; k < j+h/2; k++) {
Complex u = y[k];
Complex t = w*y[k+h/2];
y[k] = u+t;
y[k+h/2] = u-t;
w = w*wn;
}
}
}
if (on == -1)
for(int i = 0; i < len; i++)
y[i].x /= len;
}
//数组要开四倍,2n长度然后乘起来就变成4n长度的了
int num[N << 2];
char s1[N],s2[N];
int n,m;
Complex f1[N << 2],f2[N << 2];
int ans[N << 2];
void solve(char ch){
int len1 = strlen(s1);
int len2 = strlen(s2);
int len = 1;
while(len < 2 * len1 || len < 2 * len2) len <<= 1;
for(int i = 0;i < len1;++i)
{
f1[i] = Complex(s1[i] == ch,0);
}
for(int i = len1;i < len;++i)
{
f1[i] = Complex(0,0);
}
fft(f1,len,1);
for(int i = 0;i < len2;++i)
{
f2[i] = Complex(s2[i] == ch,0);
}
for(int i = len2;i < len;++i)
{
f2[i] = Complex(0,0);
}
fft(f2,len,1);
for(int i = 0;i < len;++i)
{
f1[i] = f1[i] * f2[i];
}
fft(f1,len,-1);
for(int i = 0; i < len;++i)
{
num[i] = (LL)(f1[i].x + 0.5);
}
len = len1 + len2 - 1;
for(int i = 0;i < len;++i){
ans[i] += num[i];
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
scanf("%s %s",s1,s2);
for(int i = 0;i < n;++i){
if(s1[i] == 'R'){
s1[i] = 'P';
}else if(s1[i] == 'P'){
s1[i] = 'S';
}else{
s1[i] = 'R';
}
}
reverse(s2,s2 + m);
memset(ans,0,sizeof(ans));
solve('P');
solve('S');
solve('R');
int MAX = 0;
for(int i = m - 1;i < n + m - 1;++i){
MAX = max(MAX,ans[i]);
}
printf("%d\n",MAX);
}
return 0;
}