多项式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=998244353;
  7 int n,m,n2,a[N];
  8 int Pow(int x,int p) {
  9     int ret=1;
 10     for(; p; p>>=1,x=(ll)x*x%mod)if(p&1)ret=(ll)ret*x%mod;
 11     return ret;
 12 }
 13 struct P {
 14     db x,y;
 15     P operator+(const P& b) {return {x+b.x,y+b.y};}
 16     P operator-(const P& b) {return {x-b.x,y-b.y};}
 17     P operator*(const P& b) {return {x*b.x-y*b.y,x*b.y+y*b.x};}
 18     P operator/(db b) {return {x/b,y/b};}
 19     P cj() {return {x,-y};}
 20 };
 21 struct F_FT {
 22     P A[N],B[N],w[N];
 23     int b[N],c[N],d[N],e[N],f[N];
 24     void FFT(P* a,int n,int f) {
 25         for(int i=1,j=n>>1,k; i<n-1; ++i,j^=k) {
 26             if(i<j)swap(a[i],a[j]);
 27             for(k=n>>1; j&k; j^=k,k>>=1);
 28         }
 29         for(int i=0; i<n; ++i)w[i]= {cos(2*pi*i/n),sin(2*pi*i/n)};
 30         for(int k=1; k<n; k<<=1)
 31             for(int i=0; i<n; i+=k<<1)
 32                 for(int j=i; j<i+k; ++j) {
 33                     P W= {w[n/2/k*(j-i)].x,~f?w[n/2/k*(j-i)].y:-w[n/2/k*(j-i)].y};
 34                     P x=a[j],y=W*a[j+k];
 35                     a[j]=x+y,a[j+k]=x-y;
 36                 }
 37         if(!~f)for(int i=0; i<n; ++i)a[i]=a[i]/n;
 38     }
 39     void mul(int* a,int* b,int* c,int n) {
 40         for(int i=0; i<n; ++i)A[i]= {a[i]>>15,a[i]&((1<<15)-1)},B[i]= {b[i]>>15,b[i]&((1<<15)-1)},A[i+n]= {0,0},B[i+n]= {0,0};
 41         n<<=1;
 42         FFT(A,n,1),FFT(B,n,1);
 43         for(int i=0; i<=n/2; ++i) {
 44             int j=(n-i)&(n-1);
 45             P a1=(A[i]+A[j].cj())* (P) {0.5,0},b1=(A[i]-A[j].cj())* (P) {0,-0.5};
 46             P a2=(B[i]+B[j].cj())* (P) {0.5,0},b2=(B[i]-B[j].cj())* (P) {0,-0.5};
 47             P a3=(A[j]+A[i].cj())* (P) {0.5,0},b3=(A[j]-A[i].cj())* (P) {0,-0.5};
 48             P a4=(B[j]+B[i].cj())* (P) {0.5,0},b4=(B[j]-B[i].cj())* (P) {0,-0.5};
 49             A[i]=a1*a2+b1*b2* (P) {0,1},B[i]=a1*b2+a2*b1;
 50             A[j]=a3*a4+b3*b4* (P) {0,1},B[j]=a3*b4+a4*b3;
 51         }
 52         FFT(A,n,-1),FFT(B,n,-1);
 53         for(int i=0; i<n; ++i)c[i]=(((ll(A[i].x+0.5)%mod)<<30)+ll(A[i].y+0.5)+(ll(B[i].x+0.5)<<15))%mod;
 54     }
 55     void inverse(int* a,int n) {
 56         for(int i=0; i<n; ++i)b[i]=0;
 57         b[0]=Pow(a[0],mod-2);
 58         for(int m=2; m<=n; m<<=1) {
 59             mul(b,b,c,m),mul(a,c,c,m);
 60             for(int i=0; i<m; ++i)b[i]=(((ll)b[i]*2-c[i])%mod+mod)%mod;
 61         }
 62         for(int i=0; i<n; ++i)a[i]=b[i];
 63     }
 64     void der(int* a,int n) {for(int i=1; i<n; ++i)a[i-1]=(ll)i*a[i]%mod; a[n-1]=0;}
 65     void itg(int* a,int n) {for(int i=n-2; i>=0; --i)a[i+1]=(ll)Pow(i+1,mod-2)*a[i]%mod; a[0]=0;}
 66     void log(int* a,int n) {
 67         for(int i=0; i<n; ++i)d[i]=a[i];
 68         inverse(d,n),der(a,n),mul(a,d,a,n),itg(a,n);
 69     }
 70     void exp(int* a,int n) {
 71         for(int i=0; i<n; ++i)e[i]=0;
 72         e[0]=1;
 73         for(int m=2; m<=n; m<<=1) {
 74             for(int i=0; i<m; ++i)f[i]=e[i];
 75             log(f,m);
 76             for(int i=0; i<m; ++i)f[i]=(a[i]-f[i]+mod)%mod;
 77             f[0]++;
 78             mul(e,f,e,m);
 79         }
 80         for(int i=0; i<n; ++i)a[i]=e[i];
 81     }
 82     void pow(int* a,int n,int p) {
 83         int j=0;
 84         for(; j<n&&!a[j]; ++j);
 85         if(j==n)return;
 86         int px=Pow(a[j],p),invx=Pow(a[j],mod-2);
 87         for(int i=j; i<n; ++i)a[i-j]=(ll)a[i]*invx%mod;
 88         for(int i=n-j; i<n; ++i)a[i]=0;
 89         log(a,n);
 90         for(int i=0; i<n; ++i)a[i]=(ll)a[i]*p%mod;
 91         exp(a,n);
 92         for(int i=n-1; i>=(ll)j*p; --i)a[i]=(ll)a[i-j*p]*px%mod;
 93         for(int i=0; i<n&&i<(ll)j*p; ++i)a[i]=0;
 94     }
 95 } fft;
 96 int main() {
 97     scanf("%d%d",&n,&m);
 98     for(int i=0; i<n; ++i)scanf("%d",&a[i]),a[i]%=mod;
 99     for(n2=1; n2<n; n2<<=1);
100     fft.pow(a,n2,m);
101     for(int i=0; i<n; ++i)printf("%d%c",a[i]," \n"[i==n-1]);
102     return 0;
103 }

NTT:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=4e5+10,M=1e6+10,mod=998244353;
 5 const int G=3;
 6 int n,m,n2,a[N];
 7 int Pow(int x,int p) {
 8     int ret=1;
 9     for(; p; p>>=1,x=(ll)x*x%mod)if(p&1)ret=(ll)ret*x%mod;
10     return ret;
11 }
12 struct F_FT {
13     int A[N],B[N],b[N],c[N],d[N],e[N],f[N];
14     void FFT(int* a,int n,int f) {
15         for(int i=1,j=n>>1,k; i<n-1; ++i,j^=k) {
16             if(i<j)swap(a[i],a[j]);
17             for(k=n>>1; j&k; j^=k,k>>=1);
18         }
19         for(int k=1; k<n; k<<=1) {
20             int gn=Pow(G,(mod-1)/(k<<1));
21             if(f==-1)gn=Pow(gn,mod-2);
22             for(int i=0; i<n; i+=k<<1) {
23                 int g=1;
24                 for(int j=i; j<i+k; ++j,g=(ll)g*gn%mod) {
25                     int x=a[j],y=(ll)g*a[j+k]%mod;
26                     a[j]=((ll)x+y)%mod,a[j+k]=((ll)x-y+mod)%mod;
27                 }
28             }
29         }
30         if(!~f) {
31             int invn=Pow(n,mod-2);
32             for(int i=0; i<n; ++i)a[i]=(ll)a[i]*invn%mod;
33         }
34     }
35     void mul(int* a,int* b,int* c,int n) {
36         for(int i=0; i<n; ++i)A[i]=a[i],B[i]=b[i],A[i+n]=B[i+n]=0;
37         n<<=1;
38         FFT(A,n,1),FFT(B,n,1);
39         for(int i=0; i<n; ++i)c[i]=(ll)A[i]*B[i]%mod;
40         FFT(c,n,-1);
41     }
42     void inverse(int* a,int n) {
43         for(int i=0; i<n; ++i)b[i]=0;
44         b[0]=Pow(a[0],mod-2);
45         for(int m=2; m<=n; m<<=1) {
46             for(int i=0; i<m; ++i)A[i]=a[i],B[i]=b[i],A[i+m]=B[i+m]=0;
47             FFT(A,m<<1,1),FFT(B,m<<1,1);
48             for(int i=0; i<(m<<1); ++i)b[i]=(((ll)B[i]*2-(ll)A[i]*B[i]%mod*B[i]%mod)%mod+mod)%mod;
49             FFT(b,m<<1,-1);
50             for(int i=m; i<(m<<1); ++i)b[i]=0;
51         }
52         for(int i=0; i<n; ++i)a[i]=b[i];
53     }
54     void der(int* a,int n) {for(int i=1; i<n; ++i)a[i-1]=(ll)i*a[i]%mod; a[n-1]=0;}
55     void itg(int* a,int n) {for(int i=n-2; i>=0; --i)a[i+1]=(ll)Pow(i+1,mod-2)*a[i]%mod; a[0]=0;}
56     void log(int* a,int n) {
57         for(int i=0; i<n; ++i)d[i]=a[i];
58         inverse(d,n),der(a,n),mul(a,d,a,n),itg(a,n);
59     }
60     void exp(int* a,int n) {
61         for(int i=0; i<n; ++i)e[i]=0;
62         e[0]=1;
63         for(int m=2; m<=n; m<<=1) {
64             for(int i=0; i<m; ++i)f[i]=e[i];
65             log(f,m);
66             for(int i=0; i<m; ++i)f[i]=(a[i]-f[i]+mod)%mod;
67             f[0]++;
68             mul(e,f,e,m);
69         }
70         for(int i=0; i<n; ++i)a[i]=e[i];
71     }
72     void pow(int* a,int n,int p) {
73         int j=0;
74         for(; j<n&&!a[j]; ++j);
75         if(j==n)return;
76         int px=Pow(a[j],p),invx=Pow(a[j],mod-2);
77         for(int i=j; i<n; ++i)a[i-j]=(ll)a[i]*invx%mod;
78         for(int i=n-j; i<n; ++i)a[i]=0;
79         log(a,n);
80         for(int i=0; i<n; ++i)a[i]=(ll)a[i]*p%mod;
81         exp(a,n);
82         for(int i=n-1; i>=(ll)j*p; --i)a[i]=(ll)a[i-j*p]*px%mod;
83         for(int i=0; i<n&&i<(ll)j*p; ++i)a[i]=0;
84     }
85 } fft;
86 int main() {
87     scanf("%d%d",&n,&m);
88     for(int i=0; i<n; ++i)scanf("%d",&a[i]),a[i]%=mod;
89     for(n2=1; n2<n; n2<<=1);
90     fft.pow(a,n2,m);
91     for(int i=0; i<n; ++i)printf("%d%c",a[i]," \n"[i==n-1]);
92     return 0;
93 }

代码源自洛谷P4238

原文地址:https://www.cnblogs.com/asdfsag/p/11498641.html

时间: 2024-08-29 14:20:21

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

多项式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; #de

P3811 【模板】乘法逆元

P3811 [模板]乘法逆元 题目背景 这是一道模板题 题目描述 给定n,p求1~n中所有整数在模p意义下的乘法逆元. 输入输出格式 输入格式: 一行n,p 输出格式: n行,第i行表示i在模p意义下的逆元. 输入输出样例 输入样例#1: 10 13 输出样例#1: 1 7 9 10 8 11 2 5 3 4 说明 1≤n≤3×10?6??,n<p<20000528 输入保证 p 为质数. 我们有三种办法求逆元 由欧拉定理可知 当gcd(a,n)==1 时 我们有 Aφ(n-1)≡ 1(mod

洛谷 P3811 【模板】乘法逆元 如题

P3811 [模板]乘法逆元 时空限制1s / 256MB 题目背景 这是一道模板题 题目描述 给定n,p求1~n中所有整数在模p意义下的乘法逆元. 输入输出格式 输入格式: 一行n,p 输出格式: n行,第i行表示i在模p意义下的逆元. 输入输出样例 输入样例#1: 10 13 输出样例#1: 1 7 9 10 8 11 2 5 3 4 说明 1 \leq n \leq 3 \times 10 ^ 6, n < p < 200005281≤n≤3×106,n<p<20000528

题解 P3811 【模板】乘法逆元

题意求\(i\)在模\(p\)意义下的逆元\(\frac{1}{i}\)即\(inv(i)\).题目数据范围很明显规定了要求一个线性求逆元的算法. 令\(p=ai+b\),则有: \[ai+b\equiv 0(\mod p)\] 移项得: \[ai\equiv -b(\mod p)\] 系数化简得: \[i\equiv -\frac{b}{a}(\mod p)\] 取倒数得: \[\frac{1}{i} \equiv -\frac{a}{b}(\mod p)\] 即 \[inv(i) \equi

多项式$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)$

[洛谷P3811]【模板】乘法逆元

题目大意:给你n和质数p,求1~n在模p意义下的乘法逆元(n<p). 解题思路:由于$n<p<20000528$,所以扩展欧几里得是会超时的.这儿就要用到线性推逆元大法辣!→不懂戳这里← 注意乘法可能会超过int,所以计算时先转化为long long即可. C++ Code: #include<cstdio> int n,p,inv[20000529]; int main(){ scanf("%d%d",&n,&p); puts("

T106021 【模板】乘法逆元(快速幂)

题目地址 注意点: 使用exgcd求乘法逆元需额外进行(相对)较多操作,建议使用快速幂求乘法逆元. #include<cstdio> #include<iostream> #define ll long long using namespace std; int n,p; int poww(int a,int b){ ll ans=1,tmp=a; while(b){ if(b&1){ ans*=tmp; ans%=p; } tmp=tmp*tmp; tmp%=p; b&g

luogu P3811 【模板】乘法逆元

solution 1: 费马小定理 若p为素数,a为正整数,且a.p互质,则有a^(p - 1)≡ 1(mod p) 那么a的逆元就是a^(p - 2) 用一个快速幂即可 //t两个点 #include<cstdio> using namespace std; #define int long long int p; int quickpow(int n,int k) { int ans = 1; while(k) { if(k & 1) ans = ans * n % p; n =

UVALive 7040 Color (容斥原理+逆元+组合数+费马小定理+快速幂)

题目:传送门. 题意:t组数据,每组给定n,m,k.有n个格子,m种颜色,要求把每个格子涂上颜色且正好适用k种颜色且相邻的格子颜色不同,求一共有多少种方案,结果对1e9+7取余. 题解: 首先可以将m 与后面的讨论分离.从m 种颜色中取出k 种颜色涂色,取色部分有C(m, k) 种情况: 然后通过尝试可以发现,第一个有k种选择,第二个因不能与第一个相同,只有(k-1) 种选择,第三个也只需与第二个不同,也有(k-1) 种选择.总的情况数为k ×(k-1)^(n-1).但这仅保证了相邻颜色不同,总