GYM 101667H Rock Paper Scissors(FFT)

题意:给你一个串a,是有R,S,P(石头剪刀布)构成的,然后还有一个序列b是你的出牌顺序,但你可以跳过机器的前x个出牌,从x+1开始出,问你最多赢几次

思路:好烦啊,这个题下午一直不会做,感觉和之前学弟将的一个模糊匹配的很像,但好像也不怎么像,挂机一下午。

  这个题其实是利用了卷积的性质,我们先考虑单独的每一个字母,因为我们在卷积的时候不能牵扯其他的字符,如果有其他的字符,就类似于模糊匹配了,那是我们只是用FFT加速多项式乘法,而这道题的FFT其实是用FFT算出对于(FFT后的)第i个位置,我们字符匹配后所得到的价值,所以我们把三种字符都加起来,然后取max,其实不是很难理解

代码:(逆fft的时候忘记除n,找了很久,很久不写FFT,基本忘得差不多了)

#include <bits/stdc++.h>
using namespace std;

const int N = 400005;
const double PI=acos(-1.0);
struct cp
{
    double r,i;
    cp(){}
    cp(double _r,double _i)
    {
        r=_r;i=_i;
    }
    cp operator +(const cp a)const
    {
        return cp(a.r+r,a.i+i);
    }
    cp operator -(const cp a)const
    {
        return cp(r-a.r,i-a.i);
    }
    cp operator *(const cp a)const
    {
        return cp(r*a.r-i*a.i,r*a.i+i*a.r);
    }
    cp conj()
    {
        return cp(r,-i);
    }
};

int n=1,m;
cp f[N],g[N],omg[N],inv[N];
void FFT_init(){
    for(int i=0;i<n;i++){
        omg[i]=cp(cos(2*PI*i/n),sin(2*PI*i/n));
        inv[i]=omg[i].conj();
    }
}
void fft(cp *a,cp *omg){
    int lim=0;
    while((1 << lim) < n) lim++;
    for(int i=0;i<n;i++){
        int t=0;
        for(int j=0;j<lim;j++)
            if(i >> j&1) t |= 1 << (lim - j - 1);
        if(i<t) swap(a[i],a[t]);
    }
    for(int l=2;l<=n;l*=2){
        int m=l/2;
        for(cp *p=a;p!=a+n;p+=l){
            for(int i=0;i<m;i++){
                cp t=omg[n/l*i]*p[m+i];
                p[m+i]=p[i]-t;
                p[i]=p[i]+t;
            }
        }
    }
}

int res[N],sum[N];
char a[N],b[N];
int lena,lenb;
void solve(char c)
{
    for(int i=0;i<lena;i++){
        if(a[i]==c)f[i].r=1;
        else f[i].r=0;
        f[i].i=0;
    }
    for(int i=lena;i<n;i++){
        f[i].r=0;f[i].i=0;
    }
    for(int i=0;i<lenb;i++){
        if(b[i]==c)g[i].r=1;
        else g[i].r=0;
        g[i].i=0;
    }
    for(int i=lenb;i<n;i++){
        g[i].r=0;g[i].i=0;
    }
    fft(f,omg),fft(g,omg);
    for(int i=0;i<n;i++)f[i]=f[i]*g[i];
    fft(f,inv);
    for(int i=0;i<n;i++){
        sum[i]=(int)(f[i].r/n+0.5);
    }
    for(int i=0;i<n;i++){
        res[i]+=sum[i];
    }
}
int main()
{
    scanf("%d%d",&lena,&lenb);
    scanf("%s%s",a,b);
    for(int i=0;i<lena;i++){
        if(a[i]==‘S‘)a[i]=‘R‘;
        else if(a[i]==‘R‘)a[i]=‘P‘;
        else if(a[i]==‘P‘)a[i]=‘S‘;
    }
    reverse(b,b+lenb);
    while(n<lena*2||n<lenb*2)n<<=1;
    FFT_init();
    solve(‘S‘);
    solve(‘R‘);
    solve(‘P‘);
    int ans=0;
    for(int i=lenb-1;i<lena+lenb-1;i++){
        ans=max(ans,res[i]);
    }
    printf("%d\n",ans);
    return 0;
}
/*
12 4
RSPPSSSRRPPR
RRRR
*/

原文地址:https://www.cnblogs.com/lalalatianlalu/p/9743180.html

时间: 2024-10-11 04:17:49

GYM 101667H Rock Paper Scissors(FFT)的相关文章

Hoof, Paper, Scissors(USACO)

题目大意: 一种游戏(类似于石头剪刀布):两个人分别给出一个字母,然后比较:H>S,S>P,P>H,我们已知对手的字母顺序,求在前n局中我们最多能赢多少次. 由于出字母的人非常懒,所以开局后会选定一种字母,中途只会改变k次,剩余状态下只会不停重复上一次出的字母,所以请你解决这个问题: 好吧,这道题就是DP题. f[i][j][k]表示出到第i局,改变了j次,目前出的是第k个字母的最多赢的局数. 然后每次DP可以从f[i-1][j][k]和f[i-1][j-1][l(l!=k)]转移 然后

快速傅里叶变换(FFT)

快速傅里叶变换(FFT)算法[详解] 快速傅里叶变换(Fast Fourier Transform)是信号处理与数据分析领域里最重要的算法之一.我打开一本老旧的算法书,欣赏了JW Cooley 和 John Tukey 在1965年的文章中,以看似简单的计算技巧来讲解这个东西. 本文的目标是,深入Cooley-Tukey  FFT 算法,解释作为其根源的"对称性",并以一些直观的python代码将其理论转变为实际.我希望这次研究能对这个算法的背景原理有更全面的认识. FFT(快速傅里叶

Hdu 1402 (FFT)

题目链接 A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 12490    Accepted Submission(s): 2206 Problem Description Calculate A * B. Input Each line will contain two integers A and

洛谷P3803 【模板】多项式乘法(FFT)

P3803 [模板]多项式乘法(FFT) 题目背景 这是一道FFT模板题 题目描述 给定一个n次多项式F(x),和一个m次多项式G(x). 请求出F(x)和G(x)的卷积. 输入输出格式 输入格式: 第一行2个正整数n,m. 接下来一行n+1个数字,从低到高表示F(x)的系数. 接下来一行m+1个数字,从低到高表示G(x))的系数. 输出格式: 一行n+m+1个数字,从低到高表示F(x)∗G(x)的系数. 输入输出样例 输入样例#1: 复制 1 2 1 2 1 2 1 输出样例#1: 复制 1

BZOJ[3527],[ZJOI2014]力(FFT)

BZOJ[3527],[ZJOI2014]力(FFT) 题意: 给出\(n\)个数\(q_i\),给出\(Fj\)的定义如下: \(F_j=\sum \limits _ {i < j} \frac{q_iq_j}{(i-j)^2}-\sum \limits _{i >j} \frac{q_iq_j}{(i-j)^2}.\) 令\(E_i=F_i/q_i\),求\(E_i\). 题解: 一开始没发现求\(E_i\)... 其实题目还更容易想了... \(E_i=\sum\limits _{j&l

【知识总结】快速傅里叶变换(FFT)

这可能是我第五次学FFT了--菜哭qwq 先给出一些个人认为非常优秀的参考资料: 一小时学会快速傅里叶变换(Fast Fourier Transform) - 知乎 小学生都能看懂的FFT!!! - 胡小兔 - 博客园 快速傅里叶变换(FFT)用于计算两个\(n\)次多项式相乘,能把复杂度从朴素的\(O(n^2)\)优化到\(O(nlog_2n)\).一个常见的应用是计算大整数相乘. 本文中所有多项式默认\(x\)为变量,其他字母均为常数.所有角均为弧度制. 一.多项式的两种表示方法 我们平时常

HDU 4609 3-idiots(FFT)

题意:给出n个正整数(数组A).每次随机选出三个数.问这三个数能组成三角形的概率为多大? 首先,我们用类似桶排计数的方法作出两个数组a,b,储存每个长度有几条边,然后对两个数组求卷积. 求出卷积后,这就代表了2条边能构成的边长度的集合了,注意,由于求卷积的时候可能把两条相同的边相加,所以最后求出的数组一定要减去这重复的部分,然后,先算x后算y等价于先算y后算x,所以要除以二. 然后,对于第三条边a[i],我们这样考虑:令它作为这三条边中最大的那条! 所以之前的卷积求出来的两边和一定会比这条边大,

傅里叶变换(FFT)的多相滤波结构实现

作者:桂. 时间:2017-09-25  14:53:01 链接:http://www.cnblogs.com/xingshansi/p/7591868.html 前言 以前在梳理信号频域变换的时候,提到逆序级联FFT(Inverse cascade FFT)的实现思路,后来分析多相滤波信道化,才发现其实Cascade FFT就是FFT的多相结构实现,在此系统梳理一下. 一.多相结构FFT实现 A-传统测频技术分析 信号的短时傅里叶变换(STFT)可表示为: 其中s为输入信号,w为对应窗函数.长

【ZOJ 3856】Goldbach(FFT)

题意:最多使用三个质数做加法和乘法,问得到X有多少种方案. 这道题的话分几种情况讨论清楚就好了. 1.只有一个数的情况,如果这个数是质数则方案数加1 2.有两个数的情况,可以将两个数做加法和乘法,加法的话将质数得到的数字做一遍FFT,乘法直接做sqrt(n) * sqrt(n)就好了 3.有三个数的情况,分别有三种方法,分别是a + b + c, a + b * c,a * b * c 对于a * b * c,暴力遍历一遍就好,对于a + b * c,首先暴力遍历下b * c,然后再将一个数的两