Rock Paper Scissors Lizard Spock(FFT匹配字符串)

Description:

Didi is a curious baby. One day, she finds a curious game, which named Rock Paper Scissors Lizard Spock.

The game is an upgraded version of the game named Rock, Paper, Scissors. Each player chooses an option . And then those players show their choices that was previously hidden at the same time. If the winner defeats the others, she gets a point.

The rules are as follows. 

Scissors cuts Paper

Paper covers Rock

Rock crushes Lizard

Lizard poisons Spock

Spock smashes Scissors

Scissors decapitates Lizard

Lizard eats Paper

Paper disproves Spock

Spock vaporizes Rock

(and as it always has) Rock crushes Scissors.

242dd42a2834349b5866a238c9ea15ce36d3be2f.jpg

(this pic is from baike.baidu.com)

But Didi is a little silly, she always loses the game. In order to keep her calm, her friend Tangtang writes down the order on a list and show it to her. Didi also writes down her order on another list, like p1.png.

(Rock-R Paper-P Scissors-S Lizard-L Spock-K)

However, Didi may skip some her friends' choices to find the position to get the most winning points of the game, like p2.png

Can you help Didi find the max points she can get?

Input:

The first line contains the list of choices of Didi's friend, the second line contains the list of choices of Didi.

(1<=len(s2)<=len(s1)<=1e6)

Output:

One line contains an integer indicating the maximum number of wining point.

忽略每行输出的末尾多余空格

样例输入1

RRRRRRRRRLLL
RRRS

样例输出1

3

样例输入2

RSSPKKLLRKPS
RSRS

样例输出2

2

传送门:戳这里

题意:一种特殊的剪刀石头布,现在有5种手势,每种手势可以赢过特定的2种手势,Didi 和她的朋友一起玩这个游戏,现在给出Didi 朋友的出招顺序S和Didi 的出招顺序T(|S|>=|T|),现在要求在S中找一个子串与T进行比较,使得Didi 赢得场数最多,要求输出赢得场数。


题解:FFT匹配字符串

首先讲一下FFT匹配字符串的原理:

令n=|T|,m=|S|,假设S的第i个位置的字符与T的第j个位置的字符匹配,则可以表示为S[i]=T[j]

可知,假设S[i...i+n-1]与T[0...n-1]匹配,则∑(S[i+j]-T[j])^2=0(0<=j<n)

再将T翻转,上式可变换为:∑(S[i+j]-T[n-1-j])^2=0(0<=j<n)

可以看到上式中i+j+n-1-j=i+n-1是一个固定值,即求卷积后res[i+n-1]的值就是S[i...i+n-1]与T[0...n-1]匹配。


再来看看这道题:

将T[x]能赢过S[y]表示为T[x]>S[y]

这道题要计算S[i...i+n-1]与T[0...n-1]匹配时,有多少个T[x]>S[y]。我们可以分开考虑,即枚举10种胜利方式,对于每种胜利方式X>Y,我们将T串中所有等于X的位置的值为1,其它位置的为0,将S串中所有等于Y的位置的为0,其它位置的值设为0。利用FFT求出∑S[i+j]T[n-1-j] (0<=j<n) ,res[i+n-1]就是S[i...i+n-1]与T[0...n-1]中Didi胜利的次数,将每次枚举的res累加,输出最大的res[i]即可。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define umap unordered_map
#define FIN freopen("in.txt","r",stdin);
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<int, LL>PIL;
typedef pair<LL, int> PLI;
typedef pair<LL, LL> PLL;
typedef pair<int, string>PIS;

const int MX = 1e6 + 5;
const int MAXL = MX * 4;

const double pi = acos (-1.0);
int len, res[MAXL], mx; //开大4倍
char s[MX], t[MX];
int a[MX], b[MX];
int T, n, m;

struct Complex {
    double r, i;
    Complex (double r = 0, double i = 0) : r (r), i (i) {};
    Complex operator+ (const Complex &rhs) {return Complex (r + rhs.r, i + rhs.i);}
    Complex operator- (const Complex &rhs) {return Complex (r - rhs.r, i - rhs.i);}
    Complex operator* (const Complex &rhs) {return Complex (r * rhs.r - i * rhs.i, i * rhs.r + r * rhs.i);}
} va[MAXL], vb[MAXL];
void rader (Complex F[], int len) { //len = 2^M,reverse F[i] with  F[j] j为i二进制反转
    int j = len >> 1;
    for (int i = 1; i < len - 1; ++i) {
        if (i < j) swap (F[i], F[j]); // reverse
        int k = len >> 1;
        while (j >= k) {
            j -= k;
            k >>= 1;
        }
        if (j < k) j += k;
    }
}
void FFT (Complex F[], int len, int t) {
    rader (F, len);
    for (int h = 2; h <= len; h <<= 1) {
        Complex wn (cos (-t * 2 * pi / h), sin (-t * 2 * pi / h) );
        for (int j = 0; j < len; j += h) {
            Complex E (1, 0); //旋转因子
            for (int k = j; k < j + h / 2; ++k) {
                Complex u = F[k];
                Complex v = E * F[k + h / 2];
                F[k] = u + v;
                F[k + h / 2] = u - v;
                E = E * wn;
            }
        }
    }
    if (t == -1) //IDFT
        for (int i = 0; i < len; ++i)
            F[i].r /= len;
}
void Conv (Complex a[], Complex b[], int len) { //求卷积
    FFT (a, len, 1);
    FFT (b, len, 1);
    for (int i = 0; i < len; ++i) a[i] = a[i] * b[i];
    FFT (a, len, -1);
}

void gao() {
    Conv (va, vb, len);
    for (int i = 0; i < len; ++i) res[i] += va[i].r + 0.5;
}



void solve (int x, int y) {
    len = 1;
    mx = n + m;
    while (len <= mx) len <<= 1; //mx为卷积后最大下标
    for (int i = 0; i < len; i++) va[i].r = va[i].i = vb[i].r = vb[i].i = 0;
    for (int i = 0; i < n; i++) va[i].r = a[i] == x ? 1 : 0;
    for (int i = 0; i < m; i++) vb[i].r = b[i] == y ? 1 : 0;
    gao();
}
int ch[1000];
char chx[10][10];
int main() {
    memset (chx, 0, sizeof (chx) );
    ch['R'] = 1;
    ch['P'] = 2;
    ch['S'] = 3;
    ch['L'] = 4;
    ch['K'] = 5;

    chx[3][2] = 1;
    chx[2][1] = 1;
    chx[1][4] = 1;
    chx[4][5] = 1;
    chx[5][3] = 1;
    chx[3][4] = 1;
    chx[4][2] = 1;
    chx[2][5] = 1;
    chx[5][1] = 1;
    chx[1][3] = 1;

    //FIN;
    while (~scanf ("%s%s", t, s) ) {
        n = strlen (s), m = strlen (t);
        reverse (s, s + n);
        memset (res, 0, sizeof (res) );
        for (int i = 0; i < n; i++) a[i] = ch[s[i]];
        for (int i = 0; i < m; i++) b[i] = ch[t[i]];
        for (int i = 1; i <= 5; i++) {
            for (int j = 1; j <= 5; j++) {
                if (chx[i][j]) solve (i, j);
            }
        }
        int ans = 0;
        for (int i = n - 1; i < m; i++) {
            ans = max (ans, res[i]);
        }
        printf ("%d\n", ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_31759205/article/details/80041930