多项式FFT相关模板

自己码了一个模板...有点辛苦...常数十分大,小心使用

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
using namespace std;
#define ll long long
#define pb push_back
ll MOD=998244353;
#define SZ 666666
ll w[2][SZ];
ll qp(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%MOD;
        a=a*a%MOD; b>>=1;
    }
    return ans;
}
int K;
void fftinit(int n)
{
    for(K=1;K<n;K<<=1);
    w[0][0]=w[0][K]=1;
    ll g=qp(3,(MOD-1)/K); //3是原根
    for(int i=1;i<K;i++) w[0][i]=w[0][i-1]*g%MOD;
    for(int i=0;i<=K;i++) w[1][i]=w[0][K-i];
}
void fft(int* x,int v)
{
    for(int i=0,j=0;i<K;i++)
    {
        if(i>j) {x[i]^=x[j]; x[j]^=x[i]; x[i]^=x[j];}
        for(int l=K>>1;(j^=l)<l;l>>=1);
    }
    for(int i=2;i<=K;i<<=1)
    {
        for(int j=0;j<K;j+=i)
        {
            for(int l=0;l<i>>1;l++)
            {
                ll t=(ll)x[j+l+(i>>1)]*w[v][K/i*l]%MOD;
                x[j+l+(i>>1)]=(x[j+l]-t+MOD)%MOD;
                x[j+l]=(x[j+l]+t)%MOD;
            }
        }
    }
    if(!v) return;
    ll rv=qp(K,MOD-2);
    for(int i=0;i<K;i++) x[i]=x[i]*rv%MOD;
}
struct poly
{
    vector<int> ps;
    int cs() {return ps.size()-1;}
    int& operator [] (int x) {return ps[x];} //ps.at(x)
    void sc(int x) {ps.resize(x+1);}
    void dbg()
    {
        bool fi=0;
        for(int i=cs();i>=0;i--)
        {
            if(!ps[i]) continue;
            if(fi)
            {
                if(i==0) printf("+%d",ps[i]);
                else if(ps[i]==1) printf("+");
                else if(ps[i]==-1) printf("-");
                else printf("+%d",ps[i]);
            }
            else
            {
                if(i==0) printf("%d",ps[i]);
                else if(ps[i]==1);
                else if(ps[i]==-1) printf("-");
                else printf("%d",ps[i]);
            }
            if(i>1) printf("x^%d",i);
            else if(i==1) printf("x");
            fi=1;
        }
        if(!fi) printf("0");
        putchar(10);
    }
    void clr()
    {
        int p=cs()+1;
        while(p&&!ps[p-1]) --p;
        sc(p-1);
    }
};
ll gm(ll x)
{
    x=x%MOD;
    if(x<0) x+=MOD;
    return x;
}
namespace PolyMul{int ta[SZ],tb[SZ],tc[SZ];}
poly operator * (poly a,poly b)
{
    using namespace PolyMul;
    if(a.cs()<200||b.cs()<200)
    {
        poly g;
        g.sc(a.cs()+b.cs());
        for(int i=0;i<=a.cs();i++)
        {
            for(int j=0;j<=b.cs();j++) g[i+j]=gm(g[i+j]+a[i]*(ll)b[j]%MOD);
        }
        return g;
    }
    poly c;
    int t=a.cs()+b.cs();
    c.sc(t); fftinit(t+1);
    memset(ta,0,sizeof(int)*K);
    memset(tb,0,sizeof(int)*K);
    memset(tc,0,sizeof(int)*K);
    for(int i=a.cs();i>=0;i--) ta[i]=a[i];
    for(int i=b.cs();i>=0;i--) tb[i]=b[i];
    fft(ta,0); fft(tb,0);
    for(int i=0;i<K;i++) tc[i]=(ll)ta[i]*tb[i]%MOD;
    fft(tc,1);
    for(int i=t;i>=0;i--) c[i]=tc[i];
    c.clr();
    return c;
}
namespace PolyInv{int ay[SZ],a0[SZ],tmp[SZ];}
void ginv(int t)
{
    using namespace PolyInv;
    if(t==1) {a0[0]=qp(ay[0],MOD-2); return;}
    ginv((t+1)>>1); fftinit(t+t+3);
    memset(tmp,0,sizeof(int)*K);
    for(int i=t;i<K;i++) tmp[i]=a0[i]=0;
    for(int i=0;i<t;i++) tmp[i]=ay[i];
    fft(tmp,0); fft(a0,0);
    for(int i=0;i<K;i++) a0[i]=gm((2-(ll)tmp[i]*a0[i])%MOD*a0[i]);
    fft(a0,1);
    for(int i=t;i<K;i++) a0[i]=0;
}
poly inv(poly x)
{
    using namespace PolyInv;
    poly y; y.sc(x.cs());
    for(int i=x.cs();i>=0;i--) ay[i]=x[i];
    ginv(x.cs()+1);
    for(int i=x.cs();i>=0;i--) y[i]=a0[i];
    y.clr();
    return y;
}
poly operator + (poly a,poly b)
{
    poly w; w.sc(max(a.cs(),b.cs()));
    for(int i=a.cs();i>=0;i--) w[i]=a[i];
    for(int i=b.cs();i>=0;i--) w[i]+=b[i], w[i]=gm(w[i]);
    return w;
}
poly operator - (poly a,poly b)
{
    poly w; w.sc(max(a.cs(),b.cs()));
    for(int i=a.cs();i>=0;i--) w[i]=a[i];
    for(int i=b.cs();i>=0;i--) w[i]-=b[i], w[i]=gm(w[i]);
    w.clr();
    return w;
}
void div(poly a,poly b,poly& d,poly& r)
{
    int n=a.cs(),m=b.cs();
    if(n<m) {d.sc(0); d[0]=0; r=a; return;}
    fftinit(2*n);
    poly aa=a; reverse(aa.ps.begin(),aa.ps.end());
    poly bb=b; reverse(bb.ps.begin(),bb.ps.end());
    bb.sc(n-m); bb=inv(bb); d=aa*bb; d.sc(n-m);
    reverse(d.ps.begin(),d.ps.end()); r=a-b*d;
    r.clr();
}
poly operator / (poly a,poly b)
{
    poly d,r; div(a,b,d,r); return d;
}
poly operator % (poly a,poly b)
{
    poly d,r; div(a,b,d,r); return r;
}
poly dev(poly x)
{
    for(int i=1;i<=x.cs();i++) x[i-1]=(ll)x[i]*i%MOD;
    x.sc(x.cs()-1); return x;
}
poly inte(poly x) //C=0
{
    x.sc(x.cs()+1);
    for(int i=x.cs();i>=1;i--) x[i]=x[i-1]; x[0]=0;
    for(int i=x.cs();i>=1;i--) x[i]=(ll)x[i]*qp(i,MOD-2)%MOD;
    return x;
}
ll qz_(poly& a,ll x)
{
    ll ans=0;
    for(int i=a.cs();i>=0;i--) ans=(ans*x%MOD+a[i])%MOD;
    return gm(ans);
}
namespace PolyGetv{int xs[SZ],anss[SZ];};
void gv(poly f,int m,int* x,int* ans)
{
    //f.clr();
    if(f.cs()<=7)
    {
        for(int i=0;i<=m;i++) ans[i]=qz_(f,x[i]);
        return;
    }
    poly m0,m1,tmp;
    m0.sc(0); m1.sc(0); tmp.sc(1);
    m0[0]=m1[0]=1; tmp[1]=1;
    int hf=m/2;
    for(int i=0;i<=hf;i++) tmp[0]=gm(-x[i]), m0=m0*tmp;
    for(int i=hf+1;i<=m;i++) tmp[0]=gm(-x[i]), m1=m1*tmp;
    gv(f%m0,hf,x,ans);
    gv(f%m1,m-hf,x+hf+1,ans+hf+1);
}
vector<int> getv(poly a,vector<int> x)
{
    using namespace PolyGetv;
    a.clr();
    if(!x.size()) return vector<int>();
    int m=x.size()-1;
    for(int i=0;i<=m;i++) xs[i]=x[i];
    gv(a,m,xs,anss);
    vector<int> ans; ans.resize(m+1);
    for(int i=0;i<=m;i++) ans[i]=anss[i];
    return ans;
}
int main()
{
}

加减乘逆元除取模求导积分多点求值...感觉够用了。

大部分运算没有用题目测试过...都是小数据/目测啥的...有问题求评论告知。

相关介绍请见picks博客及上一篇FFT入门。

http://picks.logdown.com/posts/177631-fast-fourier-transform

http://picks.logdown.com/posts/189620-inverse-element-of-polynomial

http://picks.logdown.com/posts/197262-polynomial-division

http://www.cnblogs.com/zzqsblog/p/5665654.html

时间: 2024-10-25 16:58:00

多项式FFT相关模板的相关文章

多项式FFT/NTT模板(含乘法/逆元/log/exp/求导/积分/快速幂)

自己整理出来的模板 存在的问题: 1.多项式求逆常数过大(尤其是浮点数FFT) 2.log只支持f[0]=1的情况,exp只支持f[0]=0的情况 有待进一步修改和完善 FFT: 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef double db; 5 const db pi=acos(-1); 6 const int N=4e5+10,M=1e6+10,mod=9982443

FFT快速傅里叶模板

FFT快速傅里叶模板-- /* use way: assign : h(x) = f(x) * g(x) f(x):len1 g(x):len2 1. len = 1; while(len < 2 * len1 || len < 2 * len2) len <<= 1; 2. for i=0 to len1-1 : x1[i](f(i),0) for i=len1 to len-1 : x1[i](0.0) g(x) is same..... 3. fft(x1,len,1) ff

luogu P4238 多项式求逆 (模板题、FFT)

手动博客搬家: 本文发表于20181125 13:21:46, 原地址https://blog.csdn.net/suncongbo/article/details/84485718 题目链接: https://www.luogu.org/problemnew/show/P4238 题意: 给定\(n\)次多项式\(A(x)\), 求\(n\)次多项式\(B(x)\)满足\(B(x)A(x)\equiv 1(\mod x^n)\) 题解: DFT,每个数对\(998244353\)求逆元.IDF

快速傅立叶变换(FFT)相关内容汇总

FFT是近年考察非常频繁的算法,与其相关的知识点也相当多样. 这里主要是资料汇总,内容补充和总结等.具体应用应在各大OJ上做相关题目. 目录: 概述 1. 前置技能:数学基础 1.1 多项式概念与运算. 1.2 微积分初步与泰勒展开 1.3 普通型生成函数与指数型生成函数 1.4 线性代数相关(矩阵,行列式与特征多项式) 1.5 组合数与伯努利数 1.6 常系数齐次线性递推 1.7 初等数论与初等代数 1.8 卷积概念与O(n^2)求法 1.9 拉格朗日插值法 2. FFT:快速傅立叶变换算法总

数学相关模板

矩阵树定理(bzoj2467) //Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long const int maxn=400+7,mod=2007; int T,n,D[max

CodeForces 958F3 Lightsabers (hard) 启发式合并/分治 多项式 FFT

原文链接http://www.cnblogs.com/zhouzhendong/p/8835443.html 题目传送门 - CodeForces 958F3 题意 有$n$个球,球有$m$种颜色,分别编号为$1\cdots m$,现在让你从中拿$k$个球,问拿到的球的颜色所构成的可重集合有多少种不同的可能. 注意同种颜色球是等价的,但是两个颜色为$x$的球不等价于一个. $1\leq n\leq 2\times 10^5,\ \ \ \ \ 1\leq m,k\leq n$. 题解 来自Hel

多项式细节梳理&amp;模板(多项式)

基础 很久以前的多项式总结 现在的码风又变了... FFT和NTT的板子 typedef complex<double> C; const double PI=acos(-1); void FFT(C*a,R op){ for(R i=0;i<N;++i) if(i<r[i])swap(a[i],a[r[i]]); for(R i=1;i<N;i<<=1){ C wn=C(cos(PI/i),sin(PI/i)*op),w=1,t; for(R j=0;j<

多项式$fft$,$ntt$,$fwt$初步

最近在学多项式和生成函数. 上课听$lnc$大神讲还是$mengbier$. 作为多项式的前置芝士,$fft,ntt$等是必学的. 在此记录一些关于$fft,ntt,fwt$的知识及例题... FFT: 应用在处理$\sum _{i+j=k} f[i]*g[j]$的卷积上. 看网上大佬的博客,基本入了门吧. 自己的关于原理的一些见解: 多项式有系数表示和点值表示,两种表示方法可以相互转化. FFT可以在$O(n*longn)$内解决多项式乘法. 具体是,点值表示的方法应用在多项式上是$O(n)$

多项式fft、ntt、fwt 总结

做了四五天的专题,但是并没有刷下多少题.可能一开始就对多项式这块十分困扰,很多细节理解不深. 最简单的形式就是直接两个多项式相乘,也就是多项式卷积,式子是$N^2$的.多项式算法的过程就是把卷积做一种变换,在变换后各系数相称得到新系数.其实这一步变换的构造过程挺深奥的,并不是很会.对于多项式卷积的变换就是点值.于是就有了快速变换这样的算法. 细节问题出过很多.边界的问题容易弄错.一般如果是两个N项多项式相乘,得到的是一个$2*N-1$项的多项式,这是存在系数的,只不过一般我们只要N项的结果,所以