2017-2018 ACM-ICPC, Asia Daejeon Regional Contest H - Rock Paper Scissors【FFT】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42671946/article/details/101618280

题意:给你两个字符串,由RSP组成,分别代表石头剪刀布,你可以改变你开始出拳的时间(但不能小于0),求最多能赢几次。

分析:对手是s串,自己是t串,即把t串中的R换成S,S换成P,P换成R,然后在S中找一个子串匹配个数最多。

固定s不动,移动t,令X(n)=\sum _{i=0}^{m-1}s[n+i]*t[i],我们把RSP分开算3次,以R为例,s[i]=1表示这个位置是R,反之不是,t同理。然后把RSP三种情况对应求和,然后再求个最大值就可以了,问题在于如何求X(n)。

其实只需要把t数组翻转一下,就变成了X(n)=\sum _{i=0}^{m-1}s[n+i]*t[m-i+1],然后就可以了直接求卷积了,总共9次FFT就可以得到答案,最后去一个max就可以了。

#include<bits/stdc++.h>

using namespace std;
const double pi = acos(-1.0);
char s[100004], t[100004];

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);
    }
};

Complex s1[800004], s2[800004], p1[800004], p2[800004], r1[800004], r2[800004];

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;
    }
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    scanf("%s%s", s, t);
    for (int i = 0; i < m; i++) {
        if (t[i] == 'R')t[i] = 'S';
        else if (t[i] == 'S')t[i] = 'P';
        else t[i] = 'R';


        if (t[i] == 'R')r2[m - i - 1].x = 1;
        else if (t[i] == 'S')s2[m - i - 1].x = 1;
        else p2[m - i - 1].x = 1;
    }
    for (int i = 0; i < n; i++) {
        if (s[i] == 'R')r1[i].x = 1;
        else if (s[i] == 'S')s1[i].x = 1;
        else p1[i].x = 1;
    }
    int len = 1;
    while (len < 2 * (n + m)) len <<= 1;
    fft(s1, len, 1);
    fft(s2, len, 1);
    fft(p1, len, 1);
    fft(p2, len, 1);
    fft(r1, len, 1);
    fft(r2, len, 1);
    for (int i = 0; i < len; ++i) {
        s1[i] = s1[i] * s2[i];
        p1[i] = p1[i] * p2[i];
        r1[i] = r1[i] * r2[i];
    }
    fft(s1, len, -1);
    fft(p1, len, -1);
    fft(r1, len, -1);
    long long ans = 0;
    for (int i = m - 1; i < n + m + 1; i++) {
        ans = max(ans, (long long) (s1[i].x + 0.5) + (long long) (p1[i].x + 0.5) + (long long) (r1[i].x + 0.5));
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/qq_42671946/article/details/101618280