HDU 6061 RXD and functions

通过二项式,可以得出:
bk=ni=0ciCkibiasni
bk=ni=0cii!k!(ik)!biasni
k!bk=ni=0(cii!)biasik(ik)!
看上去可以用FFT快速计算 k!bk
建立两个数组
Ai=cii!
Bi=biasni(ni)!
i>n 时, Ai=Bi=0
可以得到
k!bk=k+ni=0AiBk+ni
然后卷积一下就好了。

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1<<18;
const long long mod=998244353;
const int G=3;
long long rev[MAXN],w[2][MAXN];
long long fac[MAXN],inv[MAXN];
long long A[MAXN],B[MAXN];
long long pw[MAXN],ipw[MAXN];
long long c[MAXN],ans[MAXN];
int n;

long long powmod(long long x,long long p)
{
    long long ret=1;
    while(p)
    {
        if(p&1)
            ret=ret*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return ret;
}

void init()
{
    fac[0]=1;
    for(int i=1;i<MAXN;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[MAXN-1]=powmod(fac[MAXN-1],mod-2);
    for(int i=MAXN-2;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
}

void initfft(int n)
{
    int i,k,x,y,v,dv;
    for(i=0;i<=n-1;i++)
    {
        x=i;
        y=0;
        for(k=1;k<n;k<<=1,x>>=1)
        {
            (y<<=1)|=(x&1);
        }
        rev[i]=y;
    }
    v=powmod(G,(mod-1)/n);
    dv=powmod(v,mod-2);
    w[0][0]=w[1][0]=1;
    for(i=1;i<=n-1;i++)
    {
        w[0][i]=w[0][i-1]*v%mod;
        w[1][i]=w[1][i-1]*dv%mod;
    }
}

inline void fft(long long *A,int n,int ff)
{
    int i,j,k,t,l,v,x,y;
    for(i=0;i<=n-1;i++)
    {
        if(i<rev[i])
            swap(A[i],A[rev[i]]);
    }
    for(i=1;i<n;i<<=1)
    {
        for(j=0,t=n/(i<<1);j<n;j+=(i<<1))
        {
            for(k=0,l=0;k<i;k++,l+=t)
            {
                x=A[i+j+k]*w[ff][l]%mod;
                y=A[j+k];
                A[j+k]=(x+y)%mod;
                A[i+j+k]=(y+mod-x)%mod;
            } 
        }
    }
    if(ff)
    {
        v=powmod(n,mod-2);
        for(i=0;i<=n-1;i++)
            A[i]=A[i]*v%mod;
    }
}

void move(long long *f,int bias,long long *g)
{
    int i,inv_bias,m;
    if(bias==0)
    {
        for(i=0;i<=n;i++)
            g[i]=f[i];
        return;
    }
    bias=(mod-bias)%mod;
    pw[0]=1;//pw[i]表示bias的i次方 
    for(i=1;i<=n;i++)
        pw[i]=pw[i-1]*bias%mod;
    ipw[0]=1;//ipw[i]表示bias的-i次方 
    inv_bias=powmod(bias,mod-2);
    for(i=1;i<=n;i++)
        ipw[i]=ipw[i-1]*inv_bias%mod;
    m=1;
    while(m<=2*n+2)//设置m为2的整次幂 
        m<<=1;
    for(i=0;i<=m-1;i++)
        A[i]=B[i]=0;
    initfft(m);//初始化权值 
    for(i=0;i<=n;i++)
        A[i]=f[i]*fac[i]%mod;
    for(i=0;i<=n;i++)
        B[n-i]=pw[i]*inv[i]%mod;
    fft(A,m,0);//正变换 
    fft(B,m,0);
    for(i=0;i<=m-1;i++)//卷积 
        A[i]=A[i]*B[i]%mod;
    fft(A,m,1);//逆变换 
    for(i=0;i<=n;i++)
        g[i]=A[i+n]*inv[i]%mod;
}

int main()
{
    long long i,m,x,bias;
    init();
    while(~scanf("%d",&n))
    {
        for(i=0;i<=n;i++)
            scanf("%lld",&c[i]);
        bias=0;
        scanf("%lld",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%lld",&x);
            bias=(bias+x)%mod;
        } 
        move(c,bias,ans);
        for(i=0;i<=n;i++)
            printf("%lld ",ans[i]);
        puts("");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值