前言

众所周知,NTT有几个经典的模数:469762049,998244353,1004535809469762049,998244353,1004535809469762049,998244353,1004535809
为什么这些模数被称为NTT模数呢?因为他们都是这样一个形式:
P=2a∗X+1P=2^a*X+1P=2a∗X+1
为什么要有这样一个条件呢,因为只有这样,才能找到所需的原根
所以对于一般的一个模数P=2a∗X+1P=2^a*X+1P=2a∗X+1,能适用的最大的多项式长度(包括结果)是2a2^a2a
有时候,
给出的多项式长度超过限制,我们就不能用裸的NTT了
一般有两种情况:

  • 模数是NTT模数,但是多项式长度略超出限制(比如模数是1004535809,输入多项式长度和>2097152)
  • 模数不是NTT模数,比如模数是1000000007
    这个时候任意模数NTT就非常有用了

正文

我们来分析任意模数NTT做法的思路

思路一(P不是很大的时候)

根据分析,我们发现,多项式长度为N、模数为P的时候,多项式乘法的结果每一项的值0≤x≤P2N0\le x\le P^2N0≤x≤P2N
由于NTT的复杂度是Θ(nlogn)\Theta(nlogn)Θ(nlogn)的,所以nnn的范围可以出到10510^5105以上,而对于10910^9109级别的质数,那么结果大约是102310^{23}1023级别的。如果不考虑值域,有个很好的思路是:先进行FFT,算完后取模
非常不幸的是,由于结果的值域过大,FFT的精度往往都不够(这也是为什么要使用NTT的原因,根据实测,使用long double的FFT,当值域≤1013\le 10^{13}≤1013的时候,FFT是精度较好的,值域更大的时候出错概率就会比较高了,Tip:FFT的精度并不只与值域相关,多项式长度同样会影响精度(似乎是在Pi/n这个地方损失了精度),博主对各个长度都进行了测试,取min值
写一些上界(粗略)
N=1000000N=1000000N=1000000 X=6000X=6000X=6000
N=100000N=100000N=100000 X=40000X=40000X=40000
N=10000N=10000N=10000 X=300000X=300000X=300000
N=1000N=1000N=1000 X=1000000X=1000000X=1000000
N=100N=100N=100 X=6000000X=6000000X=6000000
N=10N=10N=10 X=20000000X=20000000X=20000000
(精度值在1000000下为6000,对拍程序为NTT)
所以如果你发现质数不是很大,即P2N≤1013P^2N\le 10^{13}P2N≤1013的时候,你可以放心的FFT(本测试的多项式长度上限为10610^6106)
注意:实际对于一般的FFT,保守限制为101010^{10}1010,因为long double 可能会出现莫名的错误(博主太菜了,写的代码就出现UKE,有关using namespace std和std::的,导致精度大大下降)

思路二(基于FFT的优化)(2.6倍的普通FFT,多项式长度受限较大)

贴出一道模板题,本思路以及可以解决模板题了
洛谷模板题:任意模数NTT
我们发现FFT并不是一无是处,所以我们考虑压缩值域
设p=⌈P⌉p=\left\lceil\sqrt P\right\rceilp=⌈P​⌉
那么任何一个数都能表示成X=axp+bx(X&lt;P,ax&lt;p,bx&lt;p)X=a_xp+b_x(X&lt;P,a_x&lt;p,b_x&lt;p)X=ax​p+bx​(X<P,ax​<p,bx​<p)的形式
那么我们考虑结果的一个值,对其进行分析
V=∑(axp+bx)∗(ayp+by)=∑axayp2+(axby+bxay)p+bxby\begin{aligned} V&amp;=\sum(a_xp+b_x)*(a_yp+b_y)\\ &amp;=\sum a_xa_yp^2+(a_xb_y+b_xa_y)p+b_xb_y\\ \end{aligned}V​=∑(ax​p+bx​)∗(ay​p+by​)=∑ax​ay​p2+(ax​by​+bx​ay​)p+bx​by​​
我们对每一组系数都进行计算,容易发现NNN是10510^5105级别的,值域p&lt;40000p&lt;40000p<40000,所以可以求出各项,然后再加起来
贴出AC代码

#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
using namespace std;
namespace fast_IO
{const int IN_LEN=10000000,OUT_LEN=10000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
#define rg register
typedef long long LL;
typedef long double LD;
#define double LD
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{if(x>=10)printe(x/10);putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{if(x<0)putchar('-'),printe(-x);else printe(x);
}
const int maxn=262145;const double PI=acos((LD)-1.0);
int n,m;
struct complex
{double x,y;inline complex operator +(const complex b)const{return (complex){x+b.x,y+b.y};}inline complex operator -(const complex b)const{return (complex){x-b.x,y-b.y};}inline complex operator *(const complex b)const{return (complex){x*b.x-y*b.y,x*b.y+y*b.x};}
}ax[maxn],ay[maxn],bx[maxn],by[maxn];
int lenth=1,Reverse[maxn];
inline void init(const int x)
{rg int tim=0;while(lenth<=x)lenth<<=1,tim++;for(rg int i=0;i<lenth;i++)Reverse[i]=(Reverse[i>>1]>>1)|((i&1)<<(tim-1));
}
inline void FFT(complex*A,const int fla)
{for(rg int i=0;i<lenth;i++)if(i<Reverse[i])swap(A[i],A[Reverse[i]]);for(rg int i=1;i<lenth;i<<=1){const complex w=(complex){cos(PI/i),fla*sin(PI/i)};for(rg int j=0;j<lenth;j+=(i<<1)){complex K=(complex){1,0};for(rg int k=0;k<i;k++,K=K*w){const complex x=A[j+k],y=A[j+k+i]*K;A[j+k]=x+y;A[j+k+i]=x-y;}}}
}
int P,p;
int main()
{read(n),read(m),read(P);p=31624;init(n+m);for(rg int i=0;i<=n;i++){ int x;read(x);ax[i].x=x/p,bx[i].x=x%p;}for(rg int i=0;i<=m;i++){int x;read(x);ay[i].x=x/p,by[i].x=x%p;}FFT(ax,1),FFT(bx,1),FFT(ay,1),FFT(by,1);for(rg int i=0;i<lenth;i++){const complex A=ax[i],B=bx[i],C=ay[i],D=by[i];ax[i]=A*C,ay[i]=B*D;bx[i]=A*D,by[i]=B*C;}FFT(ax,-1),FFT(bx,-1),FFT(ay,-1),FFT(by,-1);for(rg int i=0;i<=n+m;i++){const LL A=ax[i].x/lenth+0.5,B=ay[i].x/lenth+0.5,C=bx[i].x/lenth+0.5,D=by[i].x/lenth+0.5;print((A%P*p%P*p%P+B%P+(C%P+D%P)*p%P)%P),putchar(' ');}return flush(),0;
}

这里又出现了UKE!!!博主太菜啦
如果p的赋值写成⌈P⌉\left\lceil\sqrt P\right\rceil⌈P​⌉,就会会在洛谷上WA两个点
如果发现我哪里写挂了,请速联系我!
效率分析,一次一般的多项式乘法共调用3次FFT函数,这里调用了8次,所以这种任意模数NTT算法常数大概是2.6左右
update by 2019.1.7:可以通过一些技巧减小精度损失以支持更多位数或在当前位数下只使用double(tip by yx2003)
详细方法:将FFT函数中的K直接预处理即可,减少乘法中的精度损失,对多项式长度较长(100000及以上) 的情况有较大优化效果
为什么呢?大概这个精度是受限两个方面:一个是值域上限的限制(在多项式长度较小,值域较大时体现),一个是多项式长度的限制(在多项式长度较大时体现)。容易发现多项式长的时候精度受限在单位根上,这个优化就是针对单位根精度的优化
提升效果:
N=100000N=100000N=100000
X=40000⇒100000X=40000\Rightarrow100000X=40000⇒100000

N=1000000N=1000000N=1000000
X=6000⇒30000X=6000\Rightarrow30000X=6000⇒30000
对于模板题的速度也能有较大提升,大约用时是原来的12\frac1221​
代码

#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
using namespace std;
namespace fast_IO
{const int IN_LEN=10000000,OUT_LEN=10000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{if(x>=10)printe(x/10);putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{if(x<0)putchar('-'),printe(-x);else printe(x);
}
const int maxn=262145;const double PI=acos((double)-1.0);
int n,m;
struct complex
{double x,y;inline complex operator +(const complex b)const{return (complex){x+b.x,y+b.y};}inline complex operator -(const complex b)const{return (complex){x-b.x,y-b.y};}inline complex operator *(const complex b)const{return (complex){x*b.x-y*b.y,x*b.y+y*b.x};}
}ax[maxn],ay[maxn],bx[maxn],by[maxn];
int lenth=1,Reverse[maxn];
complex w[maxn];
complex fw[maxn];
inline void init(const int x)
{rg int tim=0;while(lenth<=x)lenth<<=1,tim++;for(rg int i=0;i<lenth;i++)Reverse[i]=(Reverse[i>>1]>>1)|((i&1)<<(tim-1)),w[i]=(complex){cos(i*PI/lenth),sin(i*PI/lenth)},fw[i]=(complex){cos(i*PI/lenth),-sin(i*PI/lenth)};
}
complex W[maxn];
inline void FFT(complex*A,const int fla)
{for(rg int i=0;i<lenth;i++)if(i<Reverse[i])swap(A[i],A[Reverse[i]]);for(rg int i=1;i<lenth;i<<=1){if(fla==1){for(rg int k=0;k<i;k++)W[k]=w[lenth/i*k];}else{for(rg int k=0;k<i;k++)W[k]=fw[lenth/i*k];}for(rg int j=0;j<lenth;j+=(i<<1)){for(rg int k=0;k<i;k++){const complex x=A[j+k],y=W[k]*A[j+k+i];A[j+k]=x+y;A[j+k+i]=x-y;}}}
}
int P,p;
int main()
{read(n),read(m),read(P);p=31624;init(n+m);for(rg int i=0;i<=n;i++){ int x;read(x);ax[i].x=x/p,bx[i].x=x%p;}for(rg int i=0;i<=m;i++){int x;read(x);ay[i].x=x/p,by[i].x=x%p;}FFT(ax,1),FFT(bx,1),FFT(ay,1),FFT(by,1);for(rg int i=0;i<lenth;i++){const complex A=ax[i],B=bx[i],C=ay[i],D=by[i];ax[i]=A*C,ay[i]=B*D;bx[i]=A*D,by[i]=B*C;}FFT(ax,-1),FFT(bx,-1),FFT(ay,-1),FFT(by,-1);for(rg int i=0;i<=n+m;i++){const LL A=ax[i].x/lenth+0.5,B=ay[i].x/lenth+0.5,C=bx[i].x/lenth+0.5,D=by[i].x/lenth+0.5;print((A%P*p%P*p%P+B%P+(C%P+D%P)*p%P)%P),putchar(' ');}return flush(),0;
}
思路三(基于NTT的优化)

经过前面的分析,我们得知:FFT的运算结果≤NP2\le NP^2≤NP2,是102310^{23}1023级别的
我们现在换一个思路,我们选出一些NTT模数(质数)(乘积大于FFT结果的最大值),求出在这些模意义下的值分别数多少,最后通过中国剩余定理(CRT)算出在给定模数的模意义下的值(选的质数一般是:469762049,998244353,1004535809469762049,998244353,1004535809469762049,998244353,1004535809)
但是我们发现所有质数的乘积爆long long了,所以不能直接CRT
设一个数的值为AnsAnsAns,选取的三个质数分别为p1,p2,p3p_1,p_2,p_3p1​,p2​,p3​
我们通过6次DFT,3次IDFT算出在模意义下的值
Ans≡a1(modp1),Ans≡a2(modp2),Ans≡a3(modp3)Ans\equiv a_1\pmod {p_1},Ans\equiv a_2\pmod {p_2},Ans\equiv a_3\pmod {p_3}Ans≡a1​(modp1​),Ans≡a2​(modp2​),Ans≡a3​(modp3​)
根据中国剩余定理我们可以算出Ans=a4(modp1p2)Ans=a_4\pmod{p_1p_2}Ans=a4​(modp1​p2​)
设Ans=a5p1p2+a4Ans=a_5p_1p_2+a_4Ans=a5​p1​p2​+a4​,我们已知a4a_4a4​,如果能求出a5a_5a5​就能求出Ans的值
我们发现因为Ans≡a3(modp3)Ans\equiv a_3\pmod {p_3}Ans≡a3​(modp3​)
所以a5p1p2≡a3−a4(modp3)a_5p_1p_2\equiv a_3-a_4\pmod {p_3}a5​p1​p2​≡a3​−a4​(modp3​)
就能推出a5≡(a3−a4)p1−1p2−1(modp3)a_5\equiv (a_3-a_4)p_1^{-1}p_2^{-1}\pmod {p_3}a5​≡(a3​−a4​)p1−1​p2−1​(modp3​)
然后直接计算就好了
代码也非常好写(这份代码很不注重常数,只注重好写)

#include<cstdio>
#include<cctype>
#include<cstring>
#include<cmath>
namespace fast_IO
{const int IN_LEN=10000000,OUT_LEN=10000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
typedef long long LL;
#define rg register
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline T maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;
}
template <typename T> void printe(const T x)
{if(x>=10)printe(x/10);putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{if(x<0)putchar('-'),printe(-x);else printe(x);
}
const int maxn=262145;
int n,m;
struct Ntt
{LL mod,a[maxn],b[maxn];;inline LL pow(LL x,LL y){rg LL res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}int lenth,Reverse[maxn];inline void init(const int x){rg int tim=0;lenth=1;while(lenth<=x)lenth<<=1,tim++;for(rg int i=0;i<lenth;i++)Reverse[i]=(Reverse[i>>1]>>1)|((i&1)<<(tim-1));}inline void NTT(LL*A,const int fla){for(rg int i=0;i<lenth;i++)if(i<Reverse[i])swap(A[i],A[Reverse[i]]);for(rg int i=1;i<lenth;i<<=1){LL w=pow(3,(mod-1)/i/2);if(fla==-1)w=pow(w,mod-2);for(rg int j=0;j<lenth;j+=(i<<1)){LL K=1;for(rg int k=0;k<i;k++,K=K*w%mod){const LL x=A[j+k],y=A[j+k+i]*K%mod;A[j+k]=(x+y)%mod;A[j+k+i]=(mod+x-y)%mod;}}}if(fla==-1){const int inv=pow(lenth,mod-2);for(rg int i=0;i<lenth;i++)A[i]=A[i]*inv%mod;}   }
}Q[3];
LL EXgcd(const LL a,const LL b,LL &x,LL &y)
{  if(!b){x=1,y=0;return a;  }const LL res=EXgcd(b,a%b,y,x);y-=a/b*x;return res;
}
inline LL msc(LL a,LL b,LL mod)
{LL v=(a*b-(LL)((long double)a/mod*b+1e-8)*mod);return v<0?v+mod:v;
}
int N,a[3],p[3];
LL CRT()
{  LL P=1,sum=0;  for(rg int i=1;i<=N;i++)P*=p[i];for(rg int i=1;i<=N;i++)  {const LL m=P/p[i];LL x,y;EXgcd(p[i],m,x,y);sum=(sum+msc(msc(y,m,P),a[i],P))%P;}return sum;
}
int P;
int main()
{read(n),read(m),read(P);Q[0].mod=469762049,Q[0].init(n+m);Q[1].mod=998244353,Q[1].init(n+m);Q[2].mod=1004535809,Q[2].init(n+m);for(rg int i=0;i<=n;i++)read(Q[0].a[i]),Q[2].a[i]=Q[1].a[i]=Q[0].a[i];for(rg int i=0;i<=m;i++)read(Q[0].b[i]),Q[2].b[i]=Q[1].b[i]=Q[0].b[i];Q[0].NTT(Q[0].a,1),Q[0].NTT(Q[0].b,1);Q[1].NTT(Q[1].a,1),Q[1].NTT(Q[1].b,1);Q[2].NTT(Q[2].a,1),Q[2].NTT(Q[2].b,1);for(rg int i=0;i<Q[0].lenth;i++)Q[0].a[i]=(LL)Q[0].a[i]*Q[0].b[i]%Q[0].mod,Q[1].a[i]=(LL)Q[1].a[i]*Q[1].b[i]%Q[1].mod,Q[2].a[i]=(LL)Q[2].a[i]*Q[2].b[i]%Q[2].mod;Q[0].NTT(Q[0].a,-1);Q[1].NTT(Q[1].a,-1);Q[2].NTT(Q[2].a,-1);N=2,p[1]=Q[0].mod,p[2]=Q[1].mod;const int INV=Q[2].pow(Q[0].mod,Q[2].mod-2)*Q[2].pow(Q[1].mod,Q[2].mod-2)%Q[2].mod;for(rg int i=0;i<=n+m;i++){a[1]=Q[0].a[i],a[2]=Q[1].a[i];const LL ans1=CRT();const LL ans2=((Q[2].a[i]-ans1)%Q[2].mod+Q[2].mod)%Q[2].mod*INV%Q[2].mod;print((ans2*Q[0].mod%P*Q[1].mod%P+ans1)%P),putchar(' ');}return flush(),0;
}
思路四(思路二的进阶版)

容易发现,我们可以把那个ppp的次数为111的项直接合并
这样就可以从调用8次DFT优化到调用7次
这里我就不另贴代码了
(另外,优化到这里,这个算法的速度依然很慢,中国剩余定理常数过大)
另外还可以用多项式的奇技淫巧优化常数
资料参考:毛啸,IOI2016国家集训队论文《再探快速傅里叶变换》
贴出myy给的代码链接
由于7次的DFT/IDFT已经很快了,所以咕咕咕咕咕咕
以后有空闲时间再更吧
现在先贴个链接,是txc写的任意模数 NTT 和 DFT 的优化学习笔记

总结

大概是比较清真的算法,如果推出来就很好记

任意模数NTT(MTT)相关推荐

  1. 洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)

    题目链接 三模数\(NTT\): 就是多模数\(NTT\)最后\(CRT\)一下...下面两篇讲的都挺明白的. https://blog.csdn.net/kscla/article/details/ ...

  2. 任意模数ntt_MTT:任意模数NTT

    MTT:任意模数NTT 概述 有时我们用FFT处理的数据很大,而模数可以分解为\(a\cdot 2^k+1\)的形式.次数用FFT精度不够,用NTT又找不到足够大的模数,于是MTT就应运而生了. MT ...

  3. 洛谷 P4245 【模板】任意模数NTT

    洛谷 P4245 [模板]任意模数NTT 贴个板子,4次DFT. Code #include<cstdio> #include<algorithm> #include<c ...

  4. 任意模数ntt_任意模数NTT

    任意模数\(NTT\) 众所周知,为了满足单位根的性质,\(NTT\)需要质数模数,而且需要能写成\(a2^{k} + 1\)且\(2^k \ge n\) 比较常用的有\(998244353,1004 ...

  5. 任意模数ntt_【知识总结】多项式全家桶(三)(任意模数NTT)

    经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面右侧面板 "您想嘴谁" 中选择 &q ...

  6. 【知识总结】多项式全家桶(三)(任意模数NTT)

    经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...

  7. 任意模数NTT(学习笔记)

    FFTFFTFFT有时候会被卡精度?所以可能会有模数,有了模数以后就需要模数的原根. 原根是什么?(留坑待填) NTTNTTNTT有很多种解决方法 1.1.1.特殊模数 (2k+1)∣(p−1),(p ...

  8. P4245 【模板】任意模数NTT

    Luogu4245 只要做三次的NTT,快的飞起 普通NTT,做9次 #include<cstdio> #include<cstring> #include<iostre ...

  9. Power oj 2781: 上决╇ф的黑科技 (任意模数NTT|拆系数FFT)

    https://www.oj.swust.edu.cn/problem/show/2781 式子很好推 很明显卷积即可 可以使用 NTT或者拆系数FFT 这里使用的是NTT #include < ...

最新文章

  1. 10.利用STM32定时器的PWM输出功能,直接获取PWM波形。
  2. Winserver-Exception from HRESULT: 0x800A03EC
  3. Python代码如何写的更优雅
  4. aop简介-基于cglib的动态
  5. spring 配置只读事务_只读副本和Spring Data第3部分:配置两个实体管理器
  6. echarts 中 symbol 自定义图片
  7. 如何使用Putty登录安装在VirtualBox里的ubuntu 1
  8. MyCat的安装及基本使用(MySQL分库分表)
  9. 中兴3G模块 MU301
  10. rails ruby 中对于使用Savon请求web service 获取到大量json数据的处理
  11. 高中计算机课程网页修改,高中信息技术教学贯彻新课改理念
  12. 16年的长度 记录中国独立游戏
  13. 数据结构 查找 的思维导图
  14. 小红书种草模式有哪些?如何保证种草效果
  15. 可以查看计算机主要自启动项的技术,电脑中怎么查看启动项
  16. 辽宁聚能合创:抖音蓝色粉丝牌是什么等级?
  17. MATLAB实现图像灰度直方图
  18. 见缝插针php源码,见缝插针 小游戏源码
  19. js 数组从头添加到数组_如何从头开始实现JavaScript数组方法
  20. 冷存储王者,磁带当仁不让,减碳共识下的企业优选

热门文章

  1. 类文件结构-method-init和类文件结构-method-main
  2. 反射通过配置文件运行的步骤
  3. 电脑装服务器系统好处,服务器选用Linux系统的几个好处
  4. ElasticSearch(二)索引管理
  5. 搭建卷积神经网络怎么确定参数_AI入门:卷积神经网络
  6. 在 IntelliJ IDEA 中误添加自定义的 JavaDoc 标签,如何删除
  7. JavaScript字符串操作方法大全,包含ES6方法 1
  8. N-Gram的基本原理
  9. BZOJ4520:[CQOI2016]K远点对(K-D Tree)
  10. 新页面,简单的tree视图写法