P4245-[模板]任意模数多项式乘法
正題
題目鏈接:https://www.luogu.com.cn/problem/P4245
題目大意
兩個多項式,求它們的乘積模ppp。
解題思路
方法好像挺多,我用的是最簡單的一種就是,先定一個常數sqqsqqsqq(一般是q\sqrt qq?),把一個項的數xxx拆成k?sqq+rk*sqq+rk?sqq+r。然后把FFF的kkk丟進AAA,rrr丟進BBB。GGG的kkk丟進CCC,rrr丟進DDD。
然后對于A?CA*CA?C的部分就是sqq2sqq^2sqq2的部分,A?D+B?CA*D+B*CA?D+B?C就是sqqsqqsqq,C?DC*DC?D就是111。這樣下來要跑777次FFT\text{FFT}FFT,很慢但是能過,而且要開long?double\text{long double}long?double和預處理單位根不然會被卡精度。
有一個比較快的方法是變成兩個復數多項式E[x]=A[x]+B[x]?i,F[x]=C[x]+D[x]?iE[x]=A[x]+B[x]*i,F[x]=C[x]+D[x]*iE[x]=A[x]+B[x]?i,F[x]=C[x]+D[x]?i(其中iii表示?1\sqrt{-1}?1?)。然后乘起來做一下公式就可以做到333次FFT\text{FFT}FFT。
還有一個就是不會被卡精度的NTT\text{NTT}NTT方法,就是找三個有原根的模數分別跑出來,然后用CRT\text{CRT}CRT合并,這個跑的次數多,但是因為是NTT\text{NTT}NTT所以常數和第一個差不多?
時間復雜度都是O(nlog?n)O(n\log n)O(nlogn)就是常數有不同而已
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; const ll N=4e5+10,sqq=32768; const long double Pi=acos(-1); struct complex{long double x,y;complex (long double xx=0,long double yy=0){x=xx;y=yy;return;} }A[N],B[N],C[N],D[N]; complex operator+(complex a,complex b) {return complex(a.x+b.x,a.y+b.y);} complex operator-(complex a,complex b) {return complex(a.x-b.x,a.y-b.y);} complex operator*(complex a,complex b) {return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} ll n,m,p,F[N],G[N],H[N],r[N]; complex w[N]; void FFT(complex *f,ll op,ll n){for(ll i=0;i<n;i++)if(i<r[i])swap(f[i],f[r[i]]);for(ll p=2;p<=n;p<<=1){ll len=p>>1;for(ll k=0;k<n;k+=p)for(ll i=k;i<k+len;i++){complex tmp=w[n/len*(i-k)];if(op==-1)tmp.y=-tmp.y;complex tt=f[i+len]*tmp;f[i+len]=f[i]-tt;f[i]=f[i]+tt;}}if(op==-1){for(ll i=0;i<n;i++)f[i].x=(ll)(f[i].x/n+0.49);}return; } void MTT(ll *a,ll *b,ll *c,ll m,ll k){ll n=1;while(n<=m+k)n<<=1;for(ll i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)?(n>>1):0);for(ll len=1;len<n;len<<=1)for(ll i=0;i<len;i++)w[n/len*i]=complex(cos(i*Pi/len),sin(i*Pi/len));for(ll i=0;i<m;i++)A[i].x=a[i]/sqq,B[i].x=a[i]%sqq;for(ll i=0;i<k;i++)C[i].x=b[i]/sqq,D[i].x=b[i]%sqq;FFT(A,1,n);FFT(B,1,n);FFT(C,1,n);FFT(D,1,n);complex t1,t2;for(ll i=0;i<n;i++){t1=A[i]*C[i];t2=B[i]*D[i];B[i]=A[i]*D[i]+B[i]*C[i];A[i]=t1;C[i]=t2;}FFT(A,-1,n);FFT(B,-1,n);FFT(C,-1,n);for(ll i=0;i<n;i++){(c[i]+=(ll)(A[i].x)*sqq%p*sqq%p)%=p;(c[i]+=(ll)(B[i].x)*sqq%p)%=p;(c[i]+=(ll)(C[i].x))%=p;}return; } signed main() {scanf("%lld%lld%lld",&n,&m,&p);n++;m++;for(ll i=0;i<n;i++)scanf("%lld",&F[i]);for(ll i=0;i<m;i++)scanf("%lld",&G[i]);MTT(F,G,H,n,m);for(ll i=0;i<n+m-1;i++)printf("%lld ",(H[i]%p+p)%p); }總結
以上是生活随笔為你收集整理的P4245-[模板]任意模数多项式乘法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P4351-[CERC2015]Frig
- 下一篇: P3515-[POI2011]Light