题解 P4721 【【模板】分治 FFT】

shadowice1984

2018-07-02 17:17:27

Solution

多项式求逆大法好! ________________ 如果你不会生成函数那一套理论请左转问度娘 我们考虑万能的生成函数……来求这个多项式f 假设这个多项式的生成函数是$f(x)$那么我们就是要求这个多项式的生成函数 然后我们呢发现这个生成函数$f(x)$有一个非常棒的特点,就是它卷积一个$g(x)$之后整体向右移了一位 所以我们可以列出这样一个多项式方程 ## $f(x)g(x)+f_{0}=f(x)$ 然后移项 ## $(1-g(x))f(x)=f_{0}$ 由于我们只需要求出$f(x)$的前n项,所以我们可以在膜$x^{n}$的意义下进行运算 ## $(1-g(x))f(x) \equiv f_{0} (modx^n)$ 此时我们就可以两边同时乘逆元啦…… ## $f(x) \equiv f_{0}(1-g(x))^{-1} (mod x^n)$ 剩下的事情就是左转隔壁“【模板】 多项式求逆”然后粘一遍板子的事情啦…… 上代码~ ```C #include<cstdio> #include<algorithm> using namespace std;const int N=262144+10;typedef unsigned long long ll;const ll mod=998244353; int rv[N];ll rt[2][20];ll tr1[N];ll tr2[N];ll g[N];ll ig[N];int Len;int n; inline ll po(ll a,ll p){ll r=1;for(;p;p>>=1,a=a*a%mod)if(p&1)r=r*a%mod;return r;} inline void ntt(ll* a,int o,int len)//ntt { for(int i=0;i<len;i++)if(i<rv[i])swap(a[i],a[rv[i]]);ll a0,a1; for(int k=1,j=1;k<len;k<<=1,j++) for(int s=0;s<len;s+=(k<<1)) for(int i=s,w=1;i<s+k;i++,w=w*rt[o][j]%mod) a0=a[i],a1=w*a[i+k]%mod,a[i]=(a0+a1)%mod,a[i+k]=(a0+mod-a1)%mod; if(o==1){ll inv=po(len,mod-2);for(int i=0;i<len;i++)(a[i]*=inv)%=mod;} } inline void poly_inv(ll* a,ll* b,int len)//倍增多项式求逆 { b[0]=po(a[0],mod-2); for(int k=1,j=0;k<=len;k<<=1,j++) { for(int i=1;i<(k<<1);i++)rv[i]=(rv[i>>1]>>1)|((i&1)<<j); for(int i=0;i<k;i++)tr1[i]=a[i];for(int i=0;i<k;i++)tr2[i]=b[i]; ntt(tr1,0,k<<1);ntt(tr2,0,k<<1); for(int i=0;i<(k<<1);i++)b[i]=tr2[i]*(2+mod-tr1[i]*tr2[i]%mod)%mod; ntt(b,1,k<<1);for(int i=k;i<(k<<1);i++)b[i]=0; } } int main() { for(int k=2,j=1;j<=18;k<<=1,j++)rt[0][j]=po(3,(mod-1)/k); for(int k=2,j=1;j<=18;k<<=1,j++)rt[1][j]=po(332748118,(mod-1)/k); scanf("%d",&n);for(int i=1;i<n;i++)scanf("%lld",&g[i]); for(Len=1;Len<n;Len<<=1);for(int i=1;i<n;i++)g[i]=mod-g[i];(g[0]+=1)%=mod;//处理出要求逆的多项式 poly_inv(g,ig,Len); for(int i=0;i<n;i++)printf("%lld ",ig[i]);printf("\n");return 0; } ```