分治FFT/NTT 模板

题目要我们求$f[i]=\sum\limits_{j=1}^{i}f[i-j]g[j]\;mod\;998244353$

直接上$NTT$肯定是不行的,我们不能利用尚未求得的项卷积

所以要用$CDQ$分治,先递归$[l,mid]$,然后处理$[l,mid]$对$[mid+1,r]$的影响,再递归$[mid+1,r]$

当我们处理$[l,mid]$对$[mid+1,r]$的影响时,$f[i](i\in [l,mid])$的是已经求完的,所以能用$NTT$卷积

细节比较多,注意不要让$f[i](i\in [mid+1,r])$进入卷积,因为这时的$f[i]$还没有求完,会让后面的答案错误,所以要另外开一个数组记录答案

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 (1<<17)+10
  6 #define ll long long
  7 #define dd double
  8 #define inf 0x3f3f3f3f
  9 using namespace std;
 10
 11 const ll p=998244353;
 12 void exgcd(ll a,ll b,ll &x,ll &y)
 13 {
 14     if(!b){ x=1; y=0; return; }
 15     exgcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y;
 16 }
 17 ll qpow(ll x,ll y,const ll &mod)
 18 {
 19     ll ans=1;
 20     while(y){
 21         if(y&1) ans=ans*x%mod;
 22         x=x*x%mod; y>>=1;
 23     }return ans;
 24 }
 25 int gint()
 26 {
 27     int ret=0,fh=1;char c=getchar();
 28     while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();}
 29     while(c>=‘0‘&&c<=‘9‘){ret=ret*10+c-‘0‘;c=getchar();}
 30     return ret*fh;
 31 }
 32 int r[19][N1];
 33 ll A[N1],B[N1],C[N1],g[N1],f[N1],ret[N1],invl[N1],mulwn[N1],invwn[N1];
 34 void Pre(int len,int L)
 35 {
 36     int i,j;ll inv,invy;
 37     for(j=1;j<=L;j++) for(i=0;i<(1<<j);i++)
 38         r[j][i]=(r[j][i>>1]>>1)|((i&1)<<(j-1));
 39     for(i=2;i<=len;i<<=1)
 40     {
 41         mulwn[i]=qpow(3,(p-1)/i,p);
 42         exgcd(mulwn[i],p,inv,invy); invwn[i]=(inv%p+p)%p;
 43         exgcd(i,p,inv,invy); invl[i]=(inv%p+p)%p;
 44     }
 45 }
 46 void NTT(ll *s,int len,int type,int L)
 47 {
 48     int i,j,k,inv; ll w,wn,t;
 49     for(i=0;i<len;i++)
 50         if(i<r[L][i]) swap(s[i],s[r[L][i]]);
 51     for(k=2;k<=len;k<<=1)
 52     {
 53         wn=type>0?mulwn[k]:invwn[k];
 54         for(i=0;i<len;i+=k)
 55         {
 56             for(j=0,w=1;j<(k>>1);j++,w=w*wn%p)
 57             {
 58                 t=w*s[i+j+(k>>1)]%p;
 59                 s[i+j+(k>>1)]=(s[i+j]-t+p)%p;
 60                 s[i+j]=(s[i+j]+t)%p;
 61             }
 62         }
 63     }
 64     if(type==-1)
 65     for(i=0;i<len;i++)
 66         s[i]=s[i]*invl[len]%p;
 67 }
 68 void NTT_Main(int len,int L)
 69 {
 70     NTT(A,len,1,L); NTT(B,len,1,L);
 71     for(int i=0;i<len;i++) C[i]=A[i]*B[i]%p;
 72     NTT(C,len,-1,L);
 73 }
 74 ll de(int x)
 75 {
 76     ll ans=0;
 77     for(int i=1;i<=x;i++)
 78         (ans+=g[i]*f[x-i]%p)%=p;
 79     return ans;
 80 }
 81 int debug;
 82 void CDQ(int l,int r,int L)
 83 {
 84     if(l==r){ ret[l]=f[l]; return; }
 85     int mid=(l+r)>>1,i;
 86     CDQ(l,mid,L-1);
 87     if(l==0&&r==7)
 88         debug=1;
 89     for(i=l;i<=r;i++) A[i-l]=ret[i],B[i-l]=g[i-l];
 90     NTT_Main(r-l+1,L);
 91     for(i=mid+1;i<=r;i++) (f[i]+=C[i-l])%=p;
 92     CDQ(mid+1,r,L-1);
 93 }
 94
 95 int n,m,len,L;
 96 int main()
 97 {
 98     freopen("t2.in","r",stdin);
 99     scanf("%d",&n); int i; f[0]=1;
100     for(i=1;i<n;i++) g[i]=gint();
101     for(len=1,L=0;len<n;len<<=1,L++);
102     Pre(len,L);
103     CDQ(0,len-1,L);
104     for(i=0;i<n;i++) printf("%lld ",f[i]);
105     puts("");
106     return 0;
107 }

原文地址:https://www.cnblogs.com/guapisolo/p/10300591.html

时间: 2024-10-10 02:00:17

分治FFT/NTT 模板的相关文章

多项式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=9982443

FFT&amp;NTT模板

博主菜鸡,只会背模板,根本解释不来嘤嘤嘤~ FFT: #include<bits/stdc++.h> #define IL inline #define LF double using namespace std; const int N=5e6+5; const LF Pi=acos(-1.0); struct com{ LF x,y; com(LF xx=0,LF yy=0){x=xx,y=yy;} com operator+(const com &a) const{return

分治FFT/NTT

粘板子: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int MOD = 998244353; const int N = 100050; const int M = N*3; template<typename T> inline void read(T&x) { T f = 1,c =

分治FFT模板

题目链接:https://www.luogu.org/problemnew/show/P4721 总结了一下蒟蒻FFT/NTT容易写错的地方: ? 1.rev数组求错. ? 2.cdq注意顺序:先递归左, 处理左对右的影响,再递归右.(注意!这需要考虑到分治fft的原理!) ? 3.初始a数组忘了取模等各种忘取模. ? 4.NTT第二层循环i+=(1<<j)而不是i+=j ? 5.y=gnk*a[k+j]而不是a[k+j]. 接下来是AC代码 (打//标志的是曾经与现在本蒟蒻FFT写错的地方)

【模板】分治 FFT

题目大意:给定长度为 \(n - 1\) 的序列 \(g\),求 \(f\) 序列,其中 \(f\) 为 \[ f[i]=\sum_{j=1}^{i} f[i-j] g[j] \] 学会了分治 \(fft\). 发现这个式子中也含有卷积,但是这是一个递推式,即:\(f\) 数组是未知的. 考虑分治策略,即:假设已经算出区间 \([l, mid]\) 的 \(f\) 值,现在要计算区间 \([mid + 1, r]\) 的 \(f\). 考虑左半部分对右半部分的贡献,对于 \[x \in [mid

[题解] Luogu P4721 【模板】分治 FFT

分治FFT的板子为什么要求逆呢 传送门 这个想法有点\(cdq\)啊,就是考虑分治,在算一段区间的时候,我们把他分成两个一样的区间,然后先做左区间的,算完过后把左区间和\(g\)卷积一下,这样就可以算出左区间里的\(f\)对右边的贡献,然后再算右边的就好了. 手玩一组样例吧:g=[0,3,1,2](默认\(g[0] = 0\)) 一开始,只有f[0]=1 f: [1 0|0 0] 然后我们从中间分开来,先算左边的 f: [1|0|0 0] 然后在分下去我们会找到\(f[0]\),就拿这一段和\(

分治FFT

分治FFT 目的 解决这样一类式子: \[f[n] = \sum_{i = 0}^{n - 1}f[i]g[n - i]\] 算法 看上去跟普通卷积式子挺像的,但是由于计算\(f\)的每一项时都在利用它前面的项来产生贡献,所以不能一次FFT搞完.用FFT爆算复杂度\(O(n^2logn)\),比直接枚举复杂度还高-- 考虑优化这个算法,如果我们要计算区间\([l, r]\)内的\(f\)值,如果可以快速算出区间\([l, mid]\)内的\(f\)值对区间\([mid + 1, r]\)内的\(

2017 3 11 分治FFT

考试一道题的递推式为$$f[i]=\sum_{j=1}^{i} j^k \times (i-1)! \times \frac{f[i-j]}{(i-j)!}$$这显然是一个卷积的形式,但$f$需要由自己卷过来(我也不知到怎么说),以前只会生成函数的做法,但这题好像做不了(谁教教我怎么做),于是无奈的写了一发暴力,看题解发现是分治FFT.分治每层用$f[l]-f[mid]$与$a[1]-a[r-l]$做NTT.这样显然每个$f[l]-f[mid]$对$f[mid+1]-f[r]$的贡献都考虑到了.

FFT/NTT做题方法与调试技巧(+提高码题效率的一些想法)

(其实本文应该写成了"结合FFT讨论的调试技巧+码题方法",语文不好一写文章就偏题QAQ) 有意见欢迎提出,有遗漏欢迎补充! FFT(快速傅里叶变换)/NTT(数论变换)是卷积运算常见而实用的优化 但是FFT/NTT的处理过程并不像暴力运算(差不多是多项式乘法)那样能够直观地反映卷积结果的实时变化. 因此在使用FFT时将会或多或少地加大调试的难度. 如果调试程序时直接跟踪变量,每步手算结果比对,不仅会耽误大量时间,而且效果可能并不理想. 直接肉眼查错效率可能也不太高. 但也正由于FFT