====== 多项式 3 ====== ===== 倍增 FFT ===== ==== 算法简介 ==== 主要用于加速可以倍增转移的动态规划,时间复杂度 $O\left(n\log^2 n\right)$。 ==== 算法例题 ==== [[https://www.luogu.com.cn/problem/CF755G|CF755G]] === 题意 === 将 $n$ 个球排成一排。规定一个组至少包含一个球,至多包含两个相邻的球,且一个球至多属于一个组。 问从这 $n$ 个球中取 $k$ 组有多少方案,答案对 $998244353$ 取模。 === 题解 === 设 $\text{dp}(i,j)$ 表示从 $i$ 个球里选 $j$ 组的方案数。 对于第 $n$ 个球,要么不选,要么单独构成一个组,要么与第 $n-1$ 个球构成一个组,于是有状态转移方程 $$\text{dp}(i,j)=\text{dp}(i-1,j)+\text{dp}(i-1,j-1)+\text{dp}(i-1,j-2)$$ 同时将 $a+b$ 个球划分为两组 $1\sim a$ 和 $a+1\sim a+b$,根据 $a,a+1$ 是否共同为一组可得状态转移方程 $$\text{dp}(a+b,k)=\sum_{i=0}^k\text{dp}(a,i)\text{dp}(b,k-i)+\sum_{i=0}^{k-1}\text{dp}(a-1,i)\text{dp}(b-1,k-i-1)$$ 设 $F_n(x)=\sum_{i=0}^{\infty} \text{dp}(n,i)x^i$,于是有 $$F_n(x)=F_{n-1}(x)+xF_{n-1}(x)+x^2F_{n-2}(x)$$ $$F_{a+b}(x)=F_a(x)F_b(x)+xF_{a-1}(x)F_{b-1}(x)$$ $$F_{2n-2}(x)=F_{n-1}^2(x)+xF_{n-2}^2(x)$$ $$F_{2n-1}(x)=F_n(x)F_{n-1}(x)+xF_{n-1}(x)F_{n-2}(x)$$ $$F_{2n}(x)=F_n^2(x)+xF_{n-1}^2(x)$$ 于是可以 $\left(F_{n-2},F_{n-1},F_n\right)\to \left(F_{n-1},F_n,F_{n+1}\right),\left(F_{2n-2},F_{2n-1},F_{2n}\right)$ 于是用类似快速幂的算法可以 $O(k\log n\log k)$ 解决上述问题。 const int MAXN=1<<16,Mod=998244353,G=3; int quick_pow(int a,int b){ int ans=1; while(b){ if(b&1) ans=1LL*ans*a%Mod; a=1LL*a*a%Mod; b>>=1; } return ans; } int rev[MAXN],Wn[30][2]; void init(){ int m=Mod-1,lg2=0; while(m%2==0)m>>=1,lg2++; Wn[lg2][1]=quick_pow(G,m); Wn[lg2][0]=quick_pow(Wn[lg2][1],Mod-2); while(lg2){ m<<=1,lg2--; Wn[lg2][0]=1LL*Wn[lg2+1][0]*Wn[lg2+1][0]%Mod; Wn[lg2][1]=1LL*Wn[lg2+1][1]*Wn[lg2+1][1]%Mod; } } int build(int k){ int n,pos=0; while((1<>1]>>1)|((i&1)<<(pos-1)); return n; } void NTT(int *f,int n,bool type){ _for(i,0,n)if(i ===== 分治 FFT ===== ==== 算法简介 ==== $O\left(n\log^2 n\right)$ 时间解决一些难以直接使用 $\text{FFT}$ 解决的问题。 ==== 算法例题 ==== [[https://www.luogu.com.cn/problem/P4721|洛谷p4721]] === 题意 === 给定 $g_0,g_1\cdots g_{n-2}$。 已知 $f_0=1,f_{i+1}=\sum_{j=0}^{i} f_jg_{i-j}$,求 $f_0,f_1\cdots f_{n-1}$。 === 题解 === 发现转移过程可以用 $\text{CDQ}$ 分治优化,区间 $[lef,mid]$ 对区间 $[mid,rig]$ 的贡献为 $$f_{i+1}\gets \sum_{j=lef}^{mid} f_jg_{i-j}$$ 套用 $\text{NTT}$ 可以 $O(n\log n)$ 求出 $\sum_{j=lef}^{mid} f_jg_{i-j},(mid\le i\lt rig)$,于是总时间复杂度为 $O\left(n\log^2 n\right)$。 const int MAXN=1e5+5,Mod=998244353,G=3,Inv_G=332748118; int quick_pow(int a,int b){ int ans=1; while(b){ if(b&1) ans=1LL*ans*a%Mod; a=1LL*a*a%Mod; b>>=1; } return ans; } int rev[MAXN<<2]; int build(int k){ int n,pos=0; while((1<>1]>>1)|((i&1)<<(pos-1)); return n; } void NTT(int *f,int n,int type){ _for(i,0,n)if(i>1; solve(lef,mid); int n1=mid-lef,n2=rig-lef-1,n=build(n1+n2); _rep(i,0,n1)t1[i]=f[i+lef];_for(i,n1+1,n)t1[i]=0; _rep(i,0,n2)t2[i]=g[i];_for(i,n2+1,n)t2[i]=0; NTT(t1,n,1);NTT(t2,n,1); _for(i,0,n)t1[i]=1LL*t1[i]*t2[i]%Mod; NTT(t1,n,-1); _for(i,mid,rig)f[i+1]=(f[i+1]+t1[i-lef])%Mod; solve(mid+1,rig); } int main() { int n=read_int(); _for(i,0,n-1) g[i]=read_int(); f[0]=1; solve(0,n-1); _for(i,0,n) space(f[i]); return 0; } ==== 算法练习 ==== [[https://www.luogu.com.cn/problem/CF553E|CF553E]] === 题意 === - 给定一张 $n$ 个点 $m$ 条边的无重边无自环的有向图,你要从 $1$ 号点到 $n$ 号点去 - 如果你在 $t$ 时刻之后才到达 $n$ 号点,你要交 $x$ 元的罚款 - 经过每条边需要支付 $w_e$ 费用,且经过该边消耗 $k$ 个单位时间的概率为 $p_{e,k}(1\le k\le t)$ 求最优策略下到达点 $n$ 需要花费的最小费用的期望值,数据范围 $n\le 50,m\le 100,t\le 2\times 10^4$。 === 题解 === 设 $\text{dp}(i,j)$ 表示走到点 $i$ 且已经花费 $j$ 个单位时间,达到点 $n$ 还需要花费的最小费用的期望值。 $$\text{dp}(u_e,j)=\min \left(w_e+\sum_{k=1}^tp_{e,k}\text{dp}(v_e,j+k)\right)$$ 边界条件为 $\text{dp}(u_e,j)=x+\text{dis}(u,n)(j\gt t),\text{dp}(n,j)=0(j\le t)$。 设 $g(e,j)=\sum_{k=1}^tp_{e,k}\text{dp}(v_e,j+k)$,于是有 $\text{dp}(u_e,j)=\min (w_e+g(e,j))$。 考虑分治 $\text{FFT}$,先计算出 $\text{dp}(u_e,\text{mid}+1\sim \text{rig})$,在计算他们对 $g(e,\text{lef}\sim \text{mid})$ 的贡献,再计算出 $\text{dp}(u_e,\text{lef}\sim \text{mid})$。 其中,$j\in [\text{lef},\text{mid}]$,而 $j+k$ 需要不遗漏地覆盖 $[\text{mid}+1,\text{rig}]$,于是 $k\in [1,\text{rig}-\text{lef}]$。 记 $a_i=p_{e,\text{rig}-\text{lef}-i},b_i=\text{dp}(v_e,i+\text{mid}+1)$,于是 $$g(e,j)\gets \sum p_{e,k}\text{dp}(v_e,j+k)=\sum a_{\text{rig}-\text{lef}-k}b_{k+j-\text{mid}-1}$$ 递归边界为 $\text{lef}=\text{rig}$,此时用 $g(e,j)$ 更新 $\text{dp}(u_e,j)$。由于没有必要通过分治计算出 $\text{dp}(u_e,t+1\sim 2t)$,故可以分治前处理。 总时间复杂度 $O(mt\log^2 t)$。 const int MAXN=55,MAXM=105,MAXT=2e4+5; const double pi=acos(-1.0),Inf=1e9; struct complex{ double x,y; complex(double x=0.0,double y=0.0):x(x),y(y){} complex operator + (const complex &b){ return complex(x+b.x,y+b.y); } complex operator - (const complex &b){ return complex(x-b.x,y-b.y); } complex operator * (const complex &b){ return complex(x*b.x-y*b.y,x*b.y+y*b.x); } }; int rev[MAXT<<2]; int build(int k){ int n,pos=0; while((1<>1]>>1)|((i&1)<<(pos-1)); return n; } void FFT(complex *f,int n,int type){ _for(i,0,n)if(i>1; _for(k,0,edge_cnt){ int n1=rig-lef,n2=rig-mid,n=build(n1+n2-2); _for(i,0,n1)t1[i].x=p[k][n1-i],t1[i].y=0.0;_for(i,n1,n)t1[i].x=t1[i].y=0.0; _for(i,0,n2)t2[i].x=dp[edge[k].v][i+mid+1],t2[i].y=0.0;_for(i,n2,n)t2[i].x=t2[i].y=0.0; FFT(t1,n,1);FFT(t2,n,1); _for(i,0,n)t1[i]=t1[i]*t2[i]; FFT(t1,n,-1); _rep(i,lef,mid)dp2[k][i]+=t1[i+rig-lef-mid-1].x; } } void cdq(int lef,int rig){ int mid=lef+rig>>1; if(lef==rig){ _for(i,0,edge_cnt) dp[edge[i].u][mid]=min(dp[edge[i].u][mid],dp2[i][mid]+edge[i].w); return; } cdq(mid+1,rig); cal(lef,rig); cdq(lef,mid); } int main() { int n=read_int(),m=edge_cnt=read_int(),t=read_int(); double x=read_int(); _rep(i,1,n)_rep(j,1,n)dis[i][j]=Inf; _rep(i,1,n)dis[i][i]=0.0; _for(i,0,m){ edge[i].u=read_int(),edge[i].v=read_int(),edge[i].w=read_int(); _rep(j,1,t)p[i][j]=read_int()/1e5; dis[edge[i].u][edge[i].v]=edge[i].w; } _rep(k,1,n)_rep(i,1,n)_rep(j,1,n) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); _rep(i,0,t)dp[n][i]=0;_rep(i,t+1,t<<1)dp[n][i]=x; _for(i,1,n){ _rep(j,0,t)dp[i][j]=Inf; _rep(j,t+1,t<<1)dp[i][j]=x+dis[i][n]; } cal(0,t<<1); cdq(0,t); printf("%.10lf",dp[1][0]); return 0; } ===== 多项式求逆 ===== [[https://www.luogu.com.cn/problem/P4238|洛谷p4238]] ==== 算法简介 ==== 给定 $f(x)$,求 $f(x)f^{-1}(x)\equiv 1\pmod {x^n}$,时间复杂度 $O(n\log n)$。 ==== 算法实现 ==== 假设已知 $f(x)f_0^{-1}(x)\equiv 1\pmod {x^{\lceil \frac n2\rceil}}$。 由于 $f(x)f^{-1}(x)\equiv 1\pmod {x^n}$,显然有 $f(x)f^{-1}(x)\equiv 1\pmod {x^{\lceil \frac n2\rceil}}$。 于是 $f^{-1}(x)-f_0^{-1}(x)\equiv 0\pmod {x^{\lceil \frac n2\rceil}}$。 两倍同时平方,有 $f^{-2}(x)-2f^{-1}(x)f_0^{-1}(x)+f_0^{-2}(x)\equiv 0\pmod {x^n}$。 两边同时乘以 $f(x)$,有 $f^{-1}(x)\equiv f_0^{-1}(x)(2-f(x)f_0^{-1}(x))\pmod {x^n}$。 现在考虑逆元存在条件,发现只要 $[x^0]f(x)$ 的逆元存在,就可以递推出 $f(x)$ 的逆元。 于是 $f^{-1}(x)$ 存在等价于 $\left([x^0]f(x)\right)^{-1}$ 存在。 时间复杂度有 $T(n)=T\left(\frac n2\right)+O(n\log n)$,于是 $T(n)=O(n\log n)$。 递归版与递推版效率相差不大。 //递归版 int temp[MAXN<<2]; void polyinv(int *f,int *g,int n){ if(n==1) return g[0]=quick_pow(f[0],Mod-2),void(); ployinv(f,g,(n+1)>>1); int m=build(n<<1); _for(i,0,n)temp[i]=f[i];_for(i,n,m)temp[i]=0; NTT(temp,m,1);NTT(g,m,1); _for(i,0,m)g[i]=(2-1LL*temp[i]*g[i]%Mod)*g[i]%Mod; NTT(g,m,-1); _for(i,n,m)g[i]=0; } //递推版 int temp[MAXN<<2]; void polyinv(int *f,int *g,int n){ g[0]=quick_pow(f[0],Mod-2); int n1=2,n2=4,pos=2; while((n1>>1)>1]>>1)|((i&1)<<(pos-1)); _for(i,0,n1)temp[i]=f[i];_for(i,n1,n2)temp[i]=0; NTT(temp,n2,1);NTT(g,n2,1); _for(i,0,n2)g[i]=(2-1LL*temp[i]*g[i]%Mod)*g[i]%Mod; NTT(g,n2,-1); _for(i,n1,n2)g[i]=0; n1<<=1,n2<<=1,pos++; } n1>>=1; _for(i,n,n1)g[i]=0; } ===== 多项式开根 ===== [[https://www.luogu.com.cn/problem/P5277|洛谷p5277]] ==== 算法简介 ==== 给定 $g(x)$,求 $f^2(x)\equiv g(x)\pmod {x^n}$,时间复杂度 $O(n\log n)$。 ==== 算法实现 ==== 假设已知 $f_0^2(x)\equiv g(x)\pmod {x^{\lceil \frac n2\rceil}}$。 两边平方,有 $\left(f_0^2(x)-g(x)\right)\equiv 0\pmod {x^n}$。 两边加上 $4f_0^2(x)g(x)$,有 $\left(f_0^2(x)+g(x)\right)^2 \equiv 4f_0^2(x)g(x)\pmod {x^n}$。 两边除以 $4f_0^2(x)$,有 $\left(\cfrac {f_0^2(x)+g(x)}{2f_0^2(x)}\right)^2 \equiv g(x)\pmod {x^n}$。 于是有 $f(x) \equiv \cfrac {f_0^2(x)+g(x)}{2f_0^2(x)} \equiv \cfrac {f_0(x)+f_0^{-1}(x)g(x)}2\pmod {x^n}$。 现在考虑 $f(x)$ 存在条件,发现只要 $([x^0]f(x))^2 \equiv [x^0]g(x)\pmod p$ 有解即可。 考虑 $\text{BSGS}$ 求出 $[x^0]g(x)$ 对应原根的幂次,即可得到 $[x^0]f(x)$。 HASH_Table H; int bsgs(int a,int b){ H.clear(); int m=sqrt(Mod)+1,t=b,base; for(int i=1;i<=m;i++){ t=1LL*t*a%Mod; H.insert(t,i); } t=1,base=quick_pow(a,m); for(int i=1;i<=m;i++){ t=1LL*t*base%Mod; if(H.find(t)!=-1)return m*i-H.find(t); } return -1; } int temp[MAXN<<2],inv_f[MAXN<<2]; void polysqrt(int *f,int *g,int n){ f[0]=quick_pow(3,bsgs(3,g[0])/2); int n1=2,n2=4,pos=2,inv2=quick_pow(2,Mod-2); while((n1>>1)>1]>>1)|((i&1)<<(pos-1)); _for(i,0,n2)inv_f[i]=0; ployinv(f,inv_f,n1); _for(i,0,n1)temp[i]=g[i];_for(i,n1,n2)temp[i]=0; NTT(inv_f,n2,1);NTT(temp,n2,1); _for(i,0,n2)temp[i]=1LL*temp[i]*inv_f[i]%Mod; NTT(temp,n2,-1); _for(i,0,n1)f[i]=1LL*(f[i]+temp[i])*inv2%Mod; n1<<=1,n2<<=1,pos++; } n1>>=1; _for(i,n,n1)f[i]=0; } ===== 多项式对数函数 ===== [[https://www.luogu.com.cn/problem/P4725|洛谷p4725]] ==== 算法简介 ==== 给定 $f(x)$,求模 $x^n$ 意义下的 $\ln f(x)$,时间复杂度 $O(n\log n)$。 ==== 算法实现 ==== $$\mathrm{d}(\ln f(x))\equiv \frac {f^{\prime}(x)}{f(x)}\mathrm{d}x\pmod {x^n}$$ $$\ln f(x)-\ln f(0)\equiv \int_0^x f^{\prime}(t)f^{-1}(t)\mathrm{d}t\pmod {x^n}$$ 由于一般只考虑 $f(0)=1$ 的情况,同时易知 $\int f^{\prime}(x)f^{-1}(x)$ 常数项为 $0$,于是有 $$\ln f(x)\equiv \int f^{\prime}(x)f^{-1}(x)\mathrm{d}x\pmod {x^n}$$ int inv_f[MAXN<<2]; void polyln(int *f,int n){ mem(inv_f,0); ployinv(f,inv_f,n); int m=build((n-1)<<1); _rep(i,1,n)f[i-1]=1LL*f[i]*i%Mod;_for(i,n,m)f[i]=0; NTT(f,m,1);NTT(inv_f,m,1); _for(i,0,m)f[i]=1LL*f[i]*inv_f[i]%Mod; NTT(f,m,-1); for(int i=n-1;i>=0;i--)f[i]=1LL*f[i-1]*quick_pow(i,Mod-2)%Mod; f[0]=0; _for(i,n,m)f[i]=0; } ===== 多项式牛顿迭代法 ===== ==== 算法简介 ==== 给定多项式 $g(x)$,求 $f(x)$ 满足 $g(f(x))\equiv 0\pmod {x^n}$,时间复杂度 $O(n\log n)$。 ==== 算法实现 ==== 首先单独求出 $[x^0]g(f(x))\equiv 0\pmod x$。假设已知 $g(f_0(x))\equiv 0\pmod {x^{\lceil \frac n2\rceil}}$。 将 $g(x)$ 在 $f_0(x)$ 处泰勒展开,有 $$\sum_{i=0}^{\infty} \cfrac {g^{(i)}(f_0(x))}{i!}(f(x)-f_0(x))^i\equiv 0\pmod {x^n}$$ 同时有 $x^{\lceil \frac n2\rceil}\mid (f(x)-f_0(x))$,于是有 $(f(x)-f_0(x))^i\equiv 0\pmod {x^n}(i\ge 2)$。 $$\sum_{i=0}^{\infty} \cfrac {g^{(i)}(f_0(x))}{i!}(f(x)-f_0(x))^i\equiv g(f_0(x))+g^{\prime}(f_0(x))(f(x)-f_0(x))\equiv 0\pmod {x^n}$$ $$f(x)\equiv f_0(x)-\frac {g(f_0(x))}{g^{\prime}(f_0(x))}\pmod {x^n}$$ 准确来说这里把 $f_0(x)$ 当成了变元 $y$,$g^{\prime}(f_0(x))=\cfrac {\partial g}{\partial y}(y,x)$。 举个例子,$g(f_0(x))=g(y,x)=xy+x^2+x=\cfrac x{f_0(x)}+x^2+x$,$g^{\prime}(f_0(x))=\cfrac {\partial g}{\partial y}(y,x)=-\cfrac x{y^2}=-\cfrac x{f_0^2(x)}$。 ===== 多项式指数函数 ===== [[https://www.luogu.com.cn/problem/P4726|洛谷p4726]] ==== 算法简介 ==== 给定 $f(x)$,求模 $x^n$ 意义下的 $\exp f(x)$,时间复杂度 $O(n\log n)$。 ==== 算法实现 ==== 考虑牛顿迭代法,设 $F(x)\equiv \exp f(x)\pmod {x^n}$,于是有 $g(F(x))\equiv \ln F(x)-f(x)\equiv 0\pmod {x^n}$。 $$F(x)\equiv F_0(x)-\frac {g(F_0(x))}{g^{\prime}(F_0(x))}\equiv F_0(x)-\frac {\ln F_0(x)-f(x)}{\frac 1{F_0(x)}}\equiv F_0(x)\left(1+f(x)-\ln F_0(x)\right)\pmod {x^n}$$ int ln_g[MAXN<<2]; void polyexp(int *f,int *g,int n){ g[0]=1; int n1=2,n2=4,pos=2; while((n1>>1)>1)ln_g[i]=g[i];_for(i,n1>>1,n2)ln_g[i]=0; ployln(ln_g,n1); ln_g[0]=(1+f[0]-ln_g[0])%Mod; _for(i,1,n1)ln_g[i]=(f[i]-ln_g[i])%Mod; _for(i,0,n2)rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1)); NTT(g,n2,1);NTT(ln_g,n2,1); _for(i,0,n2)g[i]=1LL*g[i]*ln_g[i]%Mod; NTT(g,n2,-1); _for(i,n1,n2)g[i]=0; n1<<=1,n2<<=1,pos++; } n1>>=1; _for(i,n,n1)g[i]=0; } ===== 多项式快速幂 ===== [[https://www.luogu.com.cn/problem/P5273|洛谷p5273]] ==== 算法简介 ==== 给定 $f(x)$,求模 $x^n$ 意义下的 $f^k(x)$,时间复杂度 $O(n\log n)$。 ==== 算法实现 ==== 考虑取对数将幂次运算转化为乘法运算加速算法。而多项式取对数存在 $[x^0]f(x)=1$ 的限制,大多数情况下无法直接套用。 于是考虑选取 $f(x)$ 第一个非零的项,即为 $a_tx^t$,然后提取出 $a_tx^t$,得到下式 $$f^k(x)\equiv a_t^kx^{tk}\exp\left(k\ln \frac{f(x)}{a_tx^t}\right)\pmod {x^n}$$ 注意到如果 $k$ 为高精度数,需要同时记录 $k\bmod {p-1}$ 和 $k\bmod p$ 的结果。 其中计算 $a_t^k$ 需要 $k\bmod {p-1}$,计算 $k\ln \cfrac{f(x)}{a_tx^t}$ 需要 $k\bmod p$,同时考虑提前处理 $x^{tk}$ 次数大于 $x^n$ 的情况。 int ln_f[MAXN<<2]; void polypow(int *f,int n,int k1,int k2){ LL pos=0,posv; while(!f[pos]&&pos=pos;i--)f[i]=f[i-pos]*posv%Mod; pos=min(pos,1LL*n); _for(i,0,pos)f[i]=0; } ===== 多项式除法 ===== [[https://www.luogu.com.cn/problem/P4512|洛谷p4512]] ==== 算法简介 ==== 给定 $f(x),g(x)$,不妨记 $\text{deg}(f)=n,\text{deg}(g)=m,n\gt m$。$O(n\log n)$ 时间内求 $q(x),r(x)$ 满足 $$f(x)=q(x)g(x)+r(x)\left(\text{deg}(q)=n-m,\text{deg}(r)\lt m\right)$$ ==== 算法实现 ==== 构造函数 $f^{R}(x)=x^{\text{deg}(f)}f(\frac 1x)$,易知 $f^{R}(x)$ 与 $f(x)$ 系数恰好反转,可以 $O(n)$ 相互转化。 根据已知,有 $$f(\frac 1x)=q(\frac 1x)g(\frac 1x)+r(\frac 1x)$$ 将上式两边同时乘以 $x^n$,有 $$f^{R}(x)=q^{R}(x)g^{R}(x)+x^{n-{\text{deg}(r)}}r^{R}(x)$$ 由于 $n-{\text{deg}(r)}\ge n-m+1$,于是有 $$f^{R}(x)\equiv q^{R}(x)g^{R}(x)\pmod {x^{n-m+1}}$$ 于是可以利用多项式求逆求出 $q^{R}(x)$,然后据此求出 $q(x),r(x)$。 int temp1[MAXN<<2],temp2[MAXN<<2]; void polydiv(int *f,int *g,int *q,int *r,int n,int m){ _for(i,0,n)temp1[i]=f[n-1-i]; _for(i,0,m)temp2[i]=g[m-1-i]; ployinv(temp2,q,n-m+1); int N=build(2*n-m-1); NTT(q,N,1);NTT(temp1,N,1); _for(i,0,N)q[i]=1LL*q[i]*temp1[i]%Mod; NTT(q,N,-1); _for(i,0,N)temp1[i]=temp2[i]=0; for(int i=0,j=n-m;i ===== 多项式板子汇总 ===== namespace Poly{ const int G=3; int rev[MAXN<<2],Pool[MAXN<<3],*Wn[30]; void init(){ int lg2=0,*pos=Pool,n,w; while((1<>=1; } } int build(int k){ int n,pos=0; while((1<>1]>>1)|((i&1)<<(pos-1)); return n; } void NTT(int *f,int n,bool type){ _for(i,0,n)if(i>1); int n=build((_n-1)<<1); _for(i,(_n+1)>>1,n)g[i]=0; _for(i,0,_n)temp[i]=f[i];_for(i,_n,n)temp[i]=0; NTT(g,n,true);NTT(temp,n,true); _for(i,0,n)g[i]=(2-1LL*temp[i]*g[i]%Mod)*g[i]%Mod; NTT(g,n,false); _for(i,_n,n)g[i]=0; } void Div(const int *f,int _n,const int *g,int _m,int *q,int *r){ static int temp[MAXN<<2]; if(_n<_m){ _rep(i,0,n)r[i]=f[i]; return; } _rep(i,0,_m)temp[i]=g[_m-i]; Inv(temp,q,_n-_m+1); _rep(i,0,_n)temp[i]=f[_n-i]; Mul(q,_n-_m+1,temp,_n+1,_n-_m+1); for(int i=0,j=_n-_m;i>1); _for(i,(_n+1)>>1,_n)g[i]=0; Ln(g,temp,_n); temp[0]=(1+f[0]-temp[0])%Mod; _for(i,1,_n)temp[i]=(f[i]-temp[i])%Mod; Mul(g,(_n+1)>>1,temp,_n,_n); } void Pow(const int *f,int *g,int _n,int k1,int k2){ static int temp[MAXN<<2]; int pos=0,posv; while(!f[pos]&&pos<_n)pos++; if(1LL*pos*k2>=_n){ _for(i,0,_n)g[i]=0; return; } posv=quick_pow(f[pos],Mod-2); _for(i,pos,_n)g[i-pos]=1LL*f[i]*posv%Mod; _for(i,_n-pos,_n)g[i]=0; Ln(g,temp,_n); _for(i,0,_n)temp[i]=1LL*temp[i]*k1%Mod; Exp(temp,g,_n); pos=pos*k2,posv=quick_pow(posv,1LL*k2*(Mod-2)%(Mod-1)); for(int i=_n-1;i>=pos;i--)g[i]=1LL*g[i-pos]*posv%Mod; _for(i,0,pos)g[i]=0; } void Sqrt(const int *f,int *g,int _n){ static int temp1[MAXN<<2],temp2[MAXN<<2]; if(_n==1)return g[0]=quick_pow(G,bsgs(3,f[0])/2),void(); Sqrt(f,g,(_n+1)>>1); _for(i,(_n+1)>>1,_n)g[i]=0; _for(i,0,_n)temp1[i]=f[i]; Inv(g,temp2,_n); Mul(temp1,_n,temp2,_n); int div2=quick_pow(2,Mod-2); _for(i,0,_n)g[i]=1LL*(g[i]+temp1[i])*div2%Mod; } }