P4245-[模板]任意模数多项式乘法

1|0正题

题目链接:https://www.luogu.com.cn/problem/P4245


1|1题目大意

两个多项式,求它们的乘积模p


1|2解题思路

方法好像挺多,我用的是最简单的一种就是,先定一个常数sqq(一般是q),把一个项的数x拆成ksqq+r。然后把Fk丢进Ar丢进BGk丢进Cr丢进D
然后对于AC的部分就是sqq2的部分,AD+BC就是sqqCD就是1。这样下来要跑7FFT,很慢但是能过,而且要开long double和预处理单位根不然会被卡精度。

有一个比较快的方法是变成两个复数多项式E[x]=A[x]+B[x]i,F[x]=C[x]+D[x]i(其中i表示1)。然后乘起来做一下公式就可以做到3FFT

还有一个就是不会被卡精度的NTT方法,就是找三个有原根的模数分别跑出来,然后用CRT合并,这个跑的次数多,但是因为是NTT所以常数和第一个差不多?

时间复杂度都是O(nlogn)就是常数有不同而已


1|3code

#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); }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14261790.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示