洛谷.3803.[模板]多项式乘法(FFT)

题目链接:洛谷LOJ.
FFT相关:快速傅里叶变换(FFT)详解FFT总结从多项式乘法到快速傅里叶变换.

#include <cmath>
#include <cctype>
#include <cstdio>
#include <algorithm>
#define gc() getchar()
const int N=1e6+5;
const double PI=acos(-1);

int n,m;
struct Complex
{
    double x,y;
    Complex(double xx=0,double yy=0) {x=xx, y=yy;}
    Complex operator + (const Complex &a) {return Complex(x+a.x, y+a.y);}
    Complex operator - (const Complex &a) {return Complex(x-a.x, y-a.y);}
    Complex operator * (const Complex &a) {return Complex(x*a.x-y*a.y, x*a.y+y*a.x);}
}A[N*3],B[N*3];//size!

void Fast_Fourier_Transform(Complex *a,int lim,int opt)
{
    for(int j=0,i=0; i<lim; ++i)
    {
        if(i>j) std::swap(a[i],a[j]);
        for(int l=lim>>1; (j^=l)<l; l>>=1);
    }
    for(int i=2; i<=lim; i<<=1)//最后等于lim即整个序列的合并
    {
        int mid=i>>1;
        Complex Wn(cos(2.0*PI/i),opt*sin(2.0*PI/i)),t;
        for(int j=0; j<lim; j+=i)
        {
            Complex w(1,0);
            for(int k=0; k<mid; ++k,w=w*Wn)
                a[j+mid+k]=a[j+k]-(t=w*a[j+mid+k]),
                a[j+k]=a[j+k]+t;
        }
    }
}
inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}

int main()
{
    n=read(),m=read();
    for(int i=0; i<=n; ++i) A[i].x=(double)read();//scanf("%lf",&A[i].x);
    for(int i=0; i<=m; ++i) B[i].x=(double)read();//scanf("%lf",&B[i].x);
    int lim=1;
    while(lim<=n+m) lim<<=1;
    Fast_Fourier_Transform(A,lim,1);
    Fast_Fourier_Transform(B,lim,1);
    for(int i=0; i<=lim; ++i) A[i]=A[i]*B[i];//size!
    Fast_Fourier_Transform(A,lim,-1);
    for(int i=0; i<=n+m; ++i) printf("%d ",(int)(A[i].x/lim+0.5));

    return 0;
}

递归实现:

#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#define gc() getchar()
const int N=2e6+5;
const double PI=acos(-1.0);

int n,m;
struct Complex
{
    double x,y;
    Complex(double xx=0,double yy=0) {x=xx, y=yy;}
    Complex operator + (const Complex &a) {return Complex(x+a.x, y+a.y);}
    Complex operator - (const Complex &a) {return Complex(x-a.x, y-a.y);}
    Complex operator * (const Complex &a) {return Complex(x*a.x-y*a.y, x*a.y+y*a.x);}
}A[N],B[N];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
void Fast_Fourier_Transform(Complex *a,int lim,int type)
{
    if(lim==1) return;
    Complex a1[lim>>1],a2[lim>>1];//爆栈
    for(int i=0; i<lim; i+=2)
        a1[i>>1]=a[i], a2[i>>1]=a[i+1];
    Fast_Fourier_Transform(a1,lim>>1,type),
    Fast_Fourier_Transform(a2,lim>>1,type);
    Complex Wn(cos(2.0*PI/lim),type*sin(2.0*PI/lim)),w(1,0),t;//Wn:单位根 w:幂
    for(int i=0; i<(lim>>1); ++i,w=w*Wn)
        a[i]=a1[i]+(t=w*a2[i]),
        a[i+(lim>>1)]=a1[i]-t;
}

int main()
{
    n=read(),m=read();
    for(int i=0; i<=n; ++i) A[i].x=read();
    for(int i=0; i<=m; ++i) B[i].x=read();
    int lim=1;
    while(lim<=n+m) lim<<=1;
    Fast_Fourier_Transform(A,lim,1);
    Fast_Fourier_Transform(B,lim,1);
    for(int i=0; i<=lim; ++i) A[i]=A[i]*B[i];
    Fast_Fourier_Transform(A,lim,-1);
    for(int i=0; i<=n+m; ++i) printf("%d ",(int)(A[i].x/lim+0.5));

    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/8444779.html

时间: 2024-10-10 10:51:38

洛谷.3803.[模板]多项式乘法(FFT)的相关文章

多项式乘法(FFT)学习笔记

------------------------------------------本文只探讨多项式乘法(FFT)在信息学中的应用如有错误或不明欢迎指出或提问,在此不胜感激 多项式 1.系数表示法     一般应用最广泛的表示方式     用A(x)表示一个x-1次多项式,a[i]为$ x^i$的系数,则A(x)=$ \sum_0^{n-1}$ a[i] * $ x^i$ 仅利用这种方式求多项式乘法复杂度为O($ n^2$),不够优秀2.点值表示法     将n个互不相同的值$ x_0$...$

[uoj#34] [洛谷P3803] 多项式乘法(FFT)

新技能--FFT. 可在 \(O(nlogn)\) 时间内完成多项式在系数表达与点值表达之间的转换. 其中最关键的一点便为单位复数根,有神奇的折半性质. 多项式乘法(即为卷积)的常见形式: \[ C_n=\sum\limits_{i=0}^n A_iB_{n-i} \] 基本思路为先将系数表达 -> 点值表达 \(O(nlogn)\) 随后点值 \(O(n)\) 进行乘法运算 最后将点值表达 -> 系数表达 \(O(nlogn)\) 代码 #include<cstdio> #inc

洛谷.1919.[模板]A乘B Problem升级版(FFT)

题目链接:洛谷.BZOJ2179 //将乘数拆成 a0*10^n + a1*10^(n-1) + ... + a_n-1的形式 //可以发现多项式乘法就模拟了竖式乘法 所以用FFT即可 注意处理进位 //n位*n位最多就只有2n位了 //论putchar的速度..还是快的 #include <cmath> #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar

【C++】最近公共祖先LCA(Tarjan离线算法)&amp;&amp; 洛谷P3379LCA模板

1.前言 首先我们介绍的算法是LCA问题中的离线算法-Tarjan算法,该算法采用DFS+并查集,再看此算法之前首先你得知道并查集(尽管我相信你如果知道这个的话肯定是知道并查集的),Tarjan算法的优点在于相对稳定,时间复杂度也比较居中,也很容易理解(个人认为). 2.思想 下面详细介绍一下Tarjan算法的思想: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5.寻找与当前点

AC自动机(附洛谷P3769模板题)

首先,介绍一下AC自动机(Aho-Corasick automaton),是一种在一个文本串中寻找每一个已给出的模式串的高效算法. 在学习AC自动机之前,你需要先学习Trie树和KMP算法,因为AC自动机正式利用并结合了两者的思想. 说到实际的不同,其实AC自动机只是在Trie树上引入了一个类似KMP中next数组的东西叫做Fail指针. 对于每一个节点,Fail指针指向该节点所代表的字符串中,次长的.在Trie树中存在的后缀(因为最长的在Trie树种存在的后缀就是其本身)所代表的节点. 举例:

洛谷P3375 [模板]KMP字符串匹配

To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整

[模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂

多项式 代码 const int nsz=(int)4e5+50; const ll nmod=998244353,g=3,ginv=332748118ll; //basic math ll qp(ll a,ll b){ ll res=1; for(;b;a=a*a%nmod,b>>=1)if(b&1)res=res*a%nmod; return res; } ll inv(ll n){ return qp(n,nmod-2); } //polynomial operations //

UOJ #34 多项式乘法 FFT快速傅立叶变换

题目大意:这是一道模板题. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 using namespace std; const double PI = acos(-1.0); struct Complex{ double x,y; Complex(dou

luogu3803 多项式乘法 (FFT)

FFT讲解传送门 简单记一下做法: 1.算法流程:两式的系数表达转化为点值表达(O(nlogn))->利用点值表达使两式相乘(O(n))->将结果的点值表达转化回系数表达(O(nlogn)) 2.做法: $$目标:把一个n项多项式F(x)=\sum_{i=0}^{n-1}a_ix^i转化为\{(w^k_n,y_k)\}的点值表达,其中w^k_n为n次单位根的k次方$$ 不妨设n为2的幂次,如果不是,则可以补上系数为0的高次项 $$将a_ix^i按照幂次奇偶性分组,得到F(x)=(a_0x^0+