计蒜客 2018 宁夏ICPC Rock Paper Scissors(FFT+母函数)

Rock Paper Scissors Lizard Spock

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.

计蒜客 2018 宁夏ICPC Rock Paper Scissors(FFT+母函数)_第1张图片

(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 计蒜客 2018 宁夏ICPC Rock Paper Scissors(FFT+母函数)_第2张图片.

(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 计蒜客 2018 宁夏ICPC Rock Paper Scissors(FFT+母函数)_第3张图片

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

题目来源

2018 ACM-ICPC 中国大学生程序设计竞赛线上赛

        大致题意:石头剪子布蜥蜴斯波克。然后给你两个人分别出的手势,第一个人出的数量更多,第二个人更少。因此在比较的时候第二个人的手势可以顺势在上面滑动,即不同滑动产生不同的对应,这样会有不同的结果。现在问你,在最好的情况下,第二个人能够胜多少场。
        首先,手势只有五种,那么第二个人获胜的总场数会等于 出石头获胜的场次 + 出剪刀获胜的场次 + ... + 出斯波克获胜的场次。所以可以分为五个小问题,枚举手势,对于每一个,我只需要考虑两种状态,赢和不赢。

        然后,枚举当前手势 i,对于第一个人的每一个手势,我都可以对于数字0或者1,0表示手势i能不能够胜,1表示能胜。这样就构成了一个长度位为len1的01串A。对于第二个人的手势,把出手势i出现的位置标记为1,其余为第二个0,得到第二个01串B。
       最后,对A、B串调整之后,两个相乘得到一个串C,C相同位置的不同手势的值的和的最大值就是最后答案。

      下面,引入母函数(生成函数)来解释相乘的操作。先是回顾一下母函数,母函数就是用函数的形式去表示一个数列,例如g(x)=a0+a1*x+a2*x^2+...+an*x^n,就要g(x)表示了数列{an}。对于A、B两个串,我们也用两个母函数两表示,令A为f(x)= A0+A1*x+A2*x^2+...+An*x^n=ΣAi*x^i,B为g(x)=B0+B1*x+B2*x^2+...+Bn*x^n=ΣBi*x^i。那么,如果两个函数相乘的话,我们可以有f(x)*g(x)=(ΣAi*x^i)*(ΣBi*x^i)=ΣΣ(Ai-j*Bj)*x^i。我们提取出其中x系数为i的一项,结果就是Ai*B0+Ai-1*B1+...+A0*Bi。但是显然B的长度不会和A一样,假设B的长度为k那么就是Ai*B0+Ai-1*B1+...+Ai-k*Bk。又系数是0和1,只有两个都是1的时候结果才是1。如此一来相乘结果的意义已经比较明显了,结果的第i项就是第二个人的手势的最后一位移动到第一个人的第i位时,当前手势获胜的场数。
       两个母函数相乘就解决了结果,关键就是相乘的复杂度。运用FFT对多项式相乘进行优化,可以到O(NlogN)的复杂度。

      细节方面,根据相乘结果的含义,对于第一个人的A串,得进行加长,前后分别增加len2-1个长度。这个自己理解一下就知道了。具体见代码:

#include
#define N 2000005
#define PI acos(-1.0)
using namespace std;

map mp;
char s[N],ss[N];

namespace FFT
{
    struct Complex
    {
        double r,i;
        Complex(double real=0.0,double image=0.0)
        {
            r=real; i=image;
        }
        Complex operator + (const Complex o)
        {
            return Complex(r+o.r,i+o.i);
        }
        Complex operator - (const Complex o)
        {
            return Complex(r-o.r,i-o.i);
        }
        Complex operator * (const Complex o)
        {
            return Complex(r*o.r-i*o.i,r*o.i+i*o.r);
        }
    };

    void brc(Complex *y, int l)
    {
        register int i,j,k;
        for( i = 1, j = l / 2; i < l - 1; i++)
        {
            if (i < j) swap(y[i], y[j]);
            k = l / 2; while ( j >= k) j -= k,k /= 2;
            if (j < k) j += k;
        }
    }

    void FFT(Complex *y, int len, double on)
    {
        register int h, i, j, k;
        Complex u, t; brc(y, len);
        for(h = 2; h <= len; h <<= 1)
        {
            Complex wn(cos(on * 2 * PI / h), sin(on * 2 * PI / h));
            for(j = 0; j < len; j += h)
            {
                Complex w(1, 0);
                for(k = j; k < j + h / 2; k++)
                {
                    u = y[k]; t = w * y[k + h / 2];
                    y[k] = u + t; y[k + h / 2] = u - t;
                    w = w * wn;
                }
            }
        }
        if (on<0) for (int i = 0; i < len; i++) y[i].r/=len;
    }

    void multiply(Complex *A,int lenA,Complex *B,int lenB)
    {
        int len;
        for(len = 1; len < lenA + lenB - 1; len <<= 1);
        for (int i = lenA; i < len; i++) A[i] = 0;
        for (int i = lenB; i < len; i++) B[i] = 0;
        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);
    }
}

FFT::Complex A[N],B[N],C[5][N];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    mp['S']=0; mp['P']=1;
    mp['R']=2; mp['L']=3; mp['K']=4;
    while(cin>>s)
    {
        cin>>ss;
        int len1=strlen(s);
        int len2=strlen(ss);
        for(int i=0;i<5;i++)
        {
            using namespace FFT;
            memset(A,0,sizeof(A));
            memset(B,0,sizeof(B));
            for(int j=len2-1;j

你可能感兴趣的:(FFT/NTT/FWT,母函数)