2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FFT)

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FFT)

Weblink

https://ac.nowcoder.com/acm/contest/13506/H

Problem

你和电脑玩剪刀石头布,给定一个电脑的出拳序列 s s s 以及你的一个出拳序列 t t t ,你可以任意在电脑的出拳序列 s s s 里选择一个位置开始比赛直到序列结束,问你最多能赢多少场。

12 4
RSPPSSSRRPPR 
RRRR
3

Solution

SB题直接秒了

显然先转换为字符串匹配,即将字符串里, R R R S S S ,问我们能赢多少场,所以把电脑的出拳序列里所有的 S S S 换成 R R R P , S P,S P,S 同理,这样问题就可以转换为一个简单的字符串匹配了,然后考虑如何匹配,显然我们可以把三个分开来一个一个匹配这样匹配三次求和就行了,即每次匹配一个字母 ch ,这样简单易处理,两个字符串这一位都等于 ch 就将他置为 1,否则就置为 0。直接字符串匹配怕是失了智,这波啊,这波是模糊匹配啊,先玩一玩嘛

我们发现每次匹配(这里先匹配 S):

扫描二维码关注公众号,回复: 12992375 查看本文章
0123456
RRSPRRS
  SPSRS
  01230123456
0010001
  10101
  01234

是 2 和 0 匹配,6 和 4 匹配,好像没什么意思,但是如果我们把 t t t 翻转一下,就会变成 2 和 4 匹配,6 和 0 匹配, 2 + 4 = 6 + 0 = 6 2+4=6+0 =6 2+4=6+0=6,欸,这不就是卷积嘛 ?!!

我们知道序列的卷积为:

C ( x ) = A ( x ) ∗ B ( x ) = ∑ k = 0 n + m − 2 ( ∑ k = i + j a i b j ) x k C(x)=A(x)* B(x)=\sum_{k=0}^{n+m-2}(\sum_{k=i+j}a_ib_j)x^k C(x)=A(x)B(x)=k=0n+m2(k=i+jaibj)xk

也就是说我们只需要将 t t t 串翻转,然后直接卷(这样我们每次相当于匹配: s 0 , t m , s 1 , t m − 1 ⋯ s_0,t_m,s_1,t_{m-1}\cdots s0,tm,s1,tm1,答案就是 x 0 + m = x m x^{0+m}=x^m x0+m=xm 的系数,以此类推),答案就是三次卷积得到的序列的 i → m − 1 ∼ n + m − 2 i\to m-1\sim n+m-2 im1n+m2 中三个序列位置 i i i 的权值之和取最值。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 7, mod = 1e9 + 7;
const double PI = acos(-1.0);
int n, m;
int L, limit = 1;
int RR[N], ans[N];

struct Complex
{
    
    
    double x, y;
    Complex(double x = 0, double y = 0) : x(x), y(y) {
    
     }
}sr[N], sp[N], ss[N], tr[N], tp[N], ts[N], ansr[N], ansp[N], anss[N];

Complex operator * (Complex J, Complex Q)
{
    
    
    return Complex(J.x * Q.x - J.y * Q.y, J.x * Q.y + J.y * Q.x);

}
Complex operator - (Complex J, Complex Q)
{
    
    
    return Complex(J.x - Q.x, J.y - Q.y);

}
Complex operator + (Complex J, Complex Q)
{
    
    
    return Complex(J.x + Q.x, J.y + Q.y);

}

void FFT(Complex * A, int type)
{
    
    
    for(int i = 0; i < limit; ++ i) {
    
    
        if(i < RR[i])
            swap(A[i], A[RR[i]]);
    }
    for(int mid = 1; mid < limit; mid <<= 1) {
    
    
        Complex wn(cos(PI / mid), type * sin(PI / mid));

        for(int len = mid << 1, pos = 0; pos < limit; pos += len) {
    
    
            Complex w(1, 0);

            for(int k = 0; k < mid; ++ k, w = w * wn) {
    
    
                Complex x = A[pos + k];
                Complex y = w * A[pos + mid + k];
                A[pos + k] = x + y;
                A[pos + mid + k] = x - y;
            }
        }
    }
    if(type == -1) {
    
    
        for(int i = 0; i < limit; ++ i) {
    
    
            A[i].x /= limit;
        }
    }
}

string s, t;

int main()
{
    
    
    scanf("%d%d", &n, &m);
    cin >> s >> t;
    for(int i = 0; i < n; ++ i) {
    
    
        if(s[i] == 'R') s[i] = 'P';
        else if(s[i] == 'P') s[i] = 'S';
        else if(s[i] == 'S') s[i] = 'R';
    }
    reverse(t.begin(), t.end());
    limit = 1, L = 0;
    while(limit <= n + m) L ++ , limit <<= 1;
    for(int i = 0; i < limit; ++ i) {
    
    
        RR[i] = (RR[i >> 1] >> 1) | ((i & 1) << (L - 1));
    }
    for(int i = 0; i < n; ++ i)
        if(s[i] == 'R')  sr[i].x = 1.0;
        else sr[i].x = 0.0;
    for(int i = 0; i < m;  ++ i)
        if(t[i] == 'R')  tr[i].x = 1.0;
        else tr[i].x = 0.0;
    FFT(sr, 1);
    FFT(tr, 1);
    for(int i = 0; i <= limit; ++ i) {
    
    
        ansr[i] = sr[i] * tr[i];
    }
    FFT(ansr, -1);

    for(int i = 0; i < n; ++ i)
        if(s[i] == 'P')  sp[i].x = 1.0;
        else sp[i].x = 0.0;
    for(int i = 0; i < m; ++ i)
        if(t[i] == 'P')  tp[i].x = 1.0;
        else tp[i].x = 0.0;
    FFT(sp, 1);
    FFT(tp, 1);
    for(int i = 0; i <= limit; ++ i) {
    
    
        ansp[i] = sp[i] * tp[i];
    }
    FFT(ansp, -1);

    for(int i = 0; i < n; ++ i)
        if(s[i] == 'S')  ss[i].x = 1.0;
        else ss[i].x = 0.0;
    for(int i = 0; i < m; ++ i)
        if(t[i] == 'S')  ts[i].x = 1.0;
        else ts[i].x = 0.0;
    FFT(ss, 1);
    FFT(ts, 1);
    for(int i = 0; i <= limit; ++ i) {
    
    
        anss[i] = ss[i] * ts[i];
    }
    FFT(anss, -1);
    
    int maxx = -1;

    for(int i = m - 1; i < n + m - 1; ++ i) {
    
    
        maxx = max(maxx, (int)(ansr[i].x + 0.5) + (int)(ansp[i].x + 0.5) + (int)(anss[i].x + 0.5));
    }
    printf("%d\n", maxx);
    return 0;
}

百度一搜发现原来这是FFT求字符串匹配的模板题呀,那没事了,是我的问题,我太菜了,写的FFT题太少了…

猜你喜欢

转载自blog.csdn.net/weixin_45697774/article/details/115285845