题目链接在这里
题目大意:
你要和电脑玩剪子包袱锤,你和电脑出的序列是固定的,比如你出的永远是RRRS,电脑永远出的是RRRRRRRRSSSS。你可以选择在电脑出第i轮时开始正式比赛,求你最多能获胜多少次。
比如如下这个情况:
电脑:RSPPSSSRRPPR
你:RRRR
在如下情况的时候,你赢的次数是最多的
题目分析:
设a表示电脑的序列,b表示你的序列,将电脑序列中你能赢的序列设为1,其它的设为0,b也是。
比方说,把b中为P的设为1,则a中为R的就为1
设f(i)表示在i点开始比赛时能赢的次数,那么
把b倒过来,就得到
上面就是卷积公式,可以用fft解决。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <complex>
using namespace std;
typedef long long ll;
typedef complex<double> cp;
const int MaxN = 1e6 + 10;
const double pi = acos(-1);
cp omg[MaxN], inv[MaxN];
char a[MaxN], b[MaxN];
cp aa[MaxN], bb[MaxN];
int ans[MaxN];
int m, n;
void fft(cp *c, int n, int f) {
for (int i = 0, j = 0; i < n; ++i) {
if(i > j) swap(c[i], c[j]);
for (int k = n >> 1; (j ^= k) < k; k >>= 1);
}
for (int i = 1; i < n; i <<= 1) {
cp wn(cos(pi / i), f * sin(pi / i));
for (int j = 0; j < n; j += i << 1) {
cp w = 1;
for (int k = 0; k < i; ++k, w *= wn) {
cp t = w * c[i + j + k];
c[i + j + k] = c[j + k] - t;
c[j + k] += t;
}
}
}
if(f == -1) {
for (int i = 0; i < n; ++i) c[i] /= n;
}
}
void kk(char ch) {
int len = 1;
while (len < m + n) len <<= 1;
for (int i = 0; i < len; ++i) aa[i] = bb[i] = 0;
for (int i = 0; i < m; ++i)
if (ch == a[i]) aa[i] = 1; else aa[i] = 0;
for (int i = 0; i < n; ++i)
if (ch == b[i]) bb[i] = 1; else bb[i] = 0;
fft(aa, len, 1);
fft(bb, len, 1);
for (int i = 0; i < len; ++i)
aa[i] *= bb[i];
fft(aa, len, -1);
for (int i = 0; i < len; ++i)
ans[i] += (int)(aa[i].real() + 0.5);
}
void solve(){
for (int i = 0; i < m; ++i) {
if ('P' == a[i]) a[i] = 'S';
else if ('S' == a[i]) a[i] = 'R';
else if ('R' == a[i]) a[i] = 'P';
}
for (int i = 0; i < n / 2; ++i)
swap(b[i], b[n - i - 1]);
kk('P');
kk('R');
kk('S');
int Max = 0;
for (int i = n - 1; i < m + n - 1; ++i)
Max = max(Max, ans[i]);
printf("%d\n", Max);
}
int main(){
scanf("%d %d", &m, &n);
scanf("%s %s", a, b);
solve();
return 0;
}