FFT
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #define maxn 1000005 8 using namespace std; 9 inline int read() { 10 int x=0,f=1;char ch=getchar(); 11 for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; 12 for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; 13 return x*f; 14 } 15 double pi=acos(-1.0); 16 struct complex { 17 double x,y; 18 complex (double xx=0,double yy=0) {x=xx;y=yy;} 19 complex operator +(const complex b) const {return complex(x+b.x,y+b.y);} 20 complex operator -(const complex b) const {return complex(x-b.x,y-b.y);} 21 complex operator *(const complex b) const {return complex(x*b.x-y*b.y,x*b.y+y*b.x);} 22 }a[maxn],b[maxn]; 23 int n,m; 24 int limit=1,l,pos[maxn]; 25 void FFT(complex *A,int tp) { 26 for(int i=0;i<limit;i++) if(i<pos[i]) swap(A[i],A[pos[i]]); 27 for(int mid=1;mid<limit;mid<<=1) { 28 complex wn(cos(pi/mid),tp*sin(pi/mid)); 29 for(int R=mid<<1,j=0;j<limit;j+=R) { 30 complex w(1,0); 31 for(int k=0;k<mid;k++,w=w*wn) { 32 complex x=A[j+k],y=w*A[j+mid+k]; 33 A[j+k]=x+y; 34 A[j+mid+k]=x-y; 35 } 36 } 37 } 38 return ; 39 } 40 int main() { 41 n=read(),m=read(); 42 for(int i=0;i<=n;i++) a[i].x=read(); 43 for(int i=0;i<=m;i++) b[i].x=read(); 44 while(limit<=n+m) limit<<=1,l++; 45 for(int i=0;i<limit;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(l-1)); 46 FFT(a,1); 47 FFT(b,1); 48 for(int i=0;i<limit;i++) a[i]=a[i]*b[i]; 49 FFT(a,-1); 50 for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/limit+0.5)); 51 }
生成函数
小A有ai个价值为Ai的物品,小B有bi个价值为Ai的物品,求用两个组成价值为ci的方案数
生成函数可以解决上面的这个问题,构造两个多项式,第X的Ai次方项的系数表示价值为i的物品有多少个,对两个人分别构造,乘在一起的多项式就代表所有的方案数。
原根
定义P的原根为满足的整数g。
NTT
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #define maxn 4000001 8 #define mod 998244353 9 #define ll long long 10 using namespace std; 11 inline int read() { 12 int x=0,f=1;char ch=getchar(); 13 for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; 14 for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; 15 return x*f; 16 } 17 ll a[maxn],b[maxn],pos[maxn]; 18 ll n,m,limit=1,l,g=3; 19 ll power(ll x,ll y) { 20 ll ans=1; 21 while(y) { 22 if(y&1) ans*=x,ans%=mod; 23 x*=x,x%=mod;y>>=1; 24 } 25 return ans; 26 } 27 void NTT(ll *A,int tp) { 28 for(int i=0;i<limit;i++) if(i<pos[i]) swap(A[i],A[pos[i]]); 29 for(int mid=1;mid<limit;mid<<=1) { 30 ll wn=power(g,(mod-1)/(mid<<1)); 31 if(tp==-1) wn=power(wn,mod-2); 32 for(int j=0;j<limit;j+=(mid<<1)) { 33 ll w=1; 34 for(int k=0;k<mid;k++,w*=wn,w%=mod) { 35 ll x=A[j+k],y=w*A[j+mid+k]; 36 A[j+k]=x+y;A[j+k]=(A[j+k]%mod+mod)%mod; 37 A[j+mid+k]=x-y;A[j+mid+k]=(A[j+mid+k]%mod+mod)%mod; 38 } 39 } 40 } 41 if(tp==-1) { 42 ll ny=power(limit,mod-2); 43 for(int i=0;i<limit;i++) A[i]*=ny,A[i]=(A[i]%mod+mod)%mod; 44 } 45 } 46 int main() { 47 n=read(),m=read(); 48 for(int i=0;i<=n;i++) a[i]=read(); 49 for(int i=0;i<=m;i++) b[i]=read(); 50 while(limit<=n+m) limit<<=1,l++; 51 for(int i=0;i<limit;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(l-1)); 52 NTT(a,1); 53 NTT(b,1); 54 for(int i=0;i<limit;i++) a[i]=a[i]*b[i],a[i]=(a[i]%mod+mod)%mod; 55 NTT(a,-1); 56 for(int i=0;i<=n+m;i++) printf("%lld ",a[i]); 57 }
多项式求逆
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #define ll long long 8 #define mod 998244353 9 #define maxn 1000000 10 using namespace std; 11 inline int read() { 12 int x=0,f=1;char ch=getchar(); 13 for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; 14 for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; 15 return x*f; 16 } 17 ll g=3,limit=1,l,n; 18 ll a[maxn],b[maxn],pos[maxn],c[maxn]; 19 ll power(ll x,ll y) { 20 ll ans=1; 21 while(y) { 22 if(y&1) ans*=x,ans%=mod; 23 x*=x,x%=mod;y>>=1; 24 } 25 return ans; 26 } 27 void NTT(ll *A,int tp) { 28 for(int i=0;i<limit;i++) if(i<pos[i]) swap(A[i],A[pos[i]]); 29 for(int mid=1;mid<limit;mid<<=1) { 30 ll wn=power(g,(mod-1)/(mid<<1)); 31 if(tp==-1) wn=power(wn,mod-2); 32 for(int j=0;j<limit;j+=(mid<<1)) { 33 ll w=1; 34 for(int k=0;k<mid;k++,w*=wn,w%=mod) { 35 ll x=A[j+k],y=w*A[j+mid+k]%mod; 36 A[j+k]=x+y;A[j+k]=(A[j+k]%mod+mod)%mod; 37 A[j+mid+k]=x-y;A[j+mid+k]=(A[j+mid+k]%mod+mod)%mod; 38 } 39 } 40 } 41 if(tp==-1) { 42 ll ny=power(limit,mod-2); 43 for(int i=0;i<limit;i++) A[i]*=ny,A[i]=(A[i]%mod+mod)%mod; 44 } 45 } 46 int d[maxn]; 47 void inv(int step,ll *A,ll *B) { 48 if(step==1) {B[0]=power(A[0],mod-2);return;} 49 inv((step+1)>>1,A,B); 50 l=0,limit=1; 51 while(limit<=(step<<1)) limit<<=1,l++; 52 for(int i=0;i<limit;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(l-1)); 53 for(int i=0;i<step;i++) c[i]=A[i]; 54 for(int i=step;i<limit;i++) c[i]=0; 55 NTT(c,1);NTT(B,1); 56 for(int i=0;i<limit;i++) B[i]=((2ll-c[i]*B[i]%mod)+mod)%mod*B[i]%mod; 57 NTT(B,-1); 58 for(int i=step;i<limit;i++) B[i]=0; 59 } 60 int main() { 61 n=read(); 62 for(int i=0;i<n;i++) a[i]=read(); 63 inv(n,a,b); 64 for(int i=0;i<n;i++) printf("%lld ",b[i]); 65 }
多项式开根
1 void getsqr(ll *A,ll *B,ll len) { 2 if(len==1) {B[0]=1;return;} 3 getsqr(A,B,(len+1)>>1); 4 memset(invb,0,sizeof(invb)); 5 getinv(B,invb,len); 6 l=0,limit=1; 7 while(limit<=(len<<1)) limit<<=1,l++; 8 for(int i=0;i<limit;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(l-1)); 9 for(int i=0;i<len;i++) c[i]=A[i]; 10 for(int i=len;i<limit;i++) c[i]=0; 11 NTT(invb,1);NTT(c,1);NTT(B,1); 12 for(int i=0;i<limit;i++) {B[i]=((c[i]*invb[i]%mod)*inv2%mod+B[i]*inv2)%mod;} 13 NTT(B,-1); 14 for(int i=len;i<limit;i++) B[i]=0; 15 }