【Luogu5349】幂(分治FFT)

【Luogu5349】幂(分治FFT)

题面

洛谷

题解

把多项式每一项拆出来考虑,于是等价于要求的只有\(\sum_{i=0}^\infty i^kr^i\)
\(f(r)=\sum_{i=0}^\infty i^k r^i\),那么\(rf(r)=\sum_{i=0}^\infty r i^k r^i\)
这里默认\(a^k=0\)\(k=0\)的时候特殊处理一下就行了。
然后就可以得到:
\[\begin{aligned} (1-r)f_k(r)&=\sum_{i=0}^\infty i^kr^i-\sum_{i=0}^{\infty}i^kr^{i+1}\\ &=\sum_{i=1}^\infty i^kr^i-\sum_{i=1}^\infty (i-1)^k r^i\\ &=\sum_{i=1}^{\infty}r^i(i^k-(i-1)^k)\\ &=r\sum_{i=0}^\infty r^i ((i+1)^k-i^k)\\ &=r\sum_{i=1}^\infty r^i \sum_{j=0}^{k-1}i^j{k\choose j}\\ &=r\sum_{j=0}^{k-1}{k\choose j}\sum_{i=0}^{\infty}i^jr^i\\ &=r\sum_{j=0}^{k-1}{k\choose j}f_j(r) \end{aligned}\]
然后我们就知道了\(f_k(r)=\frac{r}{1-r}\sum_{j=0}^{k-1}{k\choose j}f_j(r)\)
然后稍微拆开一下:
\[\begin{aligned} f_k(r)&=\frac{r}{1-r}\sum_{j=0}^{k-1}\frac{k!}{j!(k-j)!}f_j(r)\\ \frac{f_k(r)}{k!}&=\sum_{i=0}^{k-1}\frac{f_j(r)}{j!}\frac{r}{(k-j)!(1-r)} \end{aligned}\]
然后就可以随意的分治\(FFT\)了,或者这个东西推一下生成函数也可以直接多项式求逆。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define MAX 300300
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int W[MAX],r[MAX];
void NTT(int *P,int len,int opt)
{
    int l=0,N;for(N=1;N<len;N<<=1)++l;
    for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    for(int i=0;i<N;++i)if(i>r[i])swap(P[i],P[r[i]]);
    for(int i=1;i<N;i<<=1)
    {
        int w=fpow(3,(MOD-1)/(i<<1));
        W[0]=1;for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
        for(int j=0,p=i<<1;j<N;j+=p)
            for(int k=0;k<i;++k)
            {
                int X=P[j+k],Y=1ll*P[i+j+k]*W[k]%MOD;
                P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
            }
    }
    if(opt==-1)
    {
        reverse(&P[1],&P[N]);
        for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
    }
}
int n,a[MAX],R,val,ans;
int A[MAX],B[MAX],f[MAX];
int jc[MAX],jv[MAX],inv[MAX];
void CDQ(int l,int r)
{
    if(l==r)
    {
        if(l==0)f[l]=1ll*val*fpow(R,MOD-2)%MOD;
        f[l]=1ll*f[l]*jc[l]%MOD;
        return;
    }
    int mid=(l+r)>>1;
    CDQ(l,mid);
    for(int i=l;i<=mid;++i)A[i-l]=1ll*f[i]*jv[i]%MOD;
    for(int i=1;i<=r-l+1;++i)B[i]=1ll*val*jv[i]%MOD;
    int len=r-l+1+mid-l+1,N;for(N=1;N<=len;)N<<=1;
    NTT(A,N,1);NTT(B,N,1);
    for(int i=0;i<N;++i)A[i]=1ll*A[i]*B[i]%MOD;
    NTT(A,N,-1);
    for(int i=mid+1;i<=r;++i)f[i]=(f[i]+A[i-l])%MOD;
    for(int i=0;i<N;++i)A[i]=B[i]=0;
    CDQ(mid+1,r);
}
int main()
{
    n=read();R=read();val=1ll*R*fpow((1+MOD-R)%MOD,MOD-2)%MOD;
    for(int i=0;i<=n;++i)a[i]=read();
    jc[0]=jv[0]=inv[0]=inv[1]=1;
    for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    CDQ(0,n);
    for(int i=0;i<=n;++i)ans=(ans+1ll*a[i]*f[i])%MOD;
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-05-06 22:07 小蒟蒻yyb 阅读(...) 评论(...) 编辑 收藏