洛谷3711:仓鼠的数学题(NTT+伯努利数)

题面
题意:给出a数组,求
nk=0Sk(x)ak
所表示多项式的每一项系数。

额,直接将伯努利数带进S里,得

=k=0nakk+1g=0kCgk+1Bgxk+1g
=k=0nakk!g=0nBgg!xk+1g(k+1g)!

设c=k+1-g,则 xc 的系数为
1c!k+1g==cakk!Bgg!

就是个卷积了。

到处膜拜大佬们的程序,总算把我程序搞对了
但有两个似乎很重要的问题还不懂。

①样例是客观存在的,我推的公式也和题解一样
为什么 B1 要等于 12

B+ B 又是什么东西

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=1001000;
const LL mo=998244353;

LL I[N],jc[N],Ijc[N];
LL E[N],D[N],B[N],F[N];
int n,rev[N];

LL cheng(LL a,LL b)
{
    LL res=1;
    for(;b;b>>=1,a=a*a%mo)
    if(b&1)
    res=res*a%mo;
    return res;
}

void init(int lim)
{
    int k=-1;
    n=1;
    while(n<lim)
    n<<=1,k++;
    for(int i=0;i<n;i++)
    rev[i]=(rev[i>>1]>>1) | ((i&1)<<k);
}

void ntt(LL *a,int ops)
{
    for(int i=0;i<n;i++)
    if(i<rev[i])
    swap(a[i],a[rev[i]]);
    for(int l=2;l<=n;l<<=1)
    {
        int m=l>>1;
        LL wn=(ops) ? cheng(3,(mo-1)/l) : cheng(3,mo-1-(mo-1)/l);
        for(int i=0;i<n;i+=l)
        {
            LL w=1;
            for(int k=0;k<m;k++)
            {
                LL t=a[i+k+m]*w%mo;
                a[i+k+m]=(a[i+k]-t+mo)%mo;
                a[i+k]=(a[i+k]+t)%mo;
                w=w*wn%mo;
            }
        }
    }
    if(!ops)
    for(int i=0;i<n;i++)
    a[i]=a[i]*I[n]%mo;
}

void ny(int x)
{
    if(x==1)
    return;

    ny(x/2);

    for(int i=0;i<x;i++)
    E[i]=B[i];
    init(x*2);
    ntt(E,1);
    ntt(D,1);
    for(int i=0;i<n;i++)
    D[i]=D[i]*(2-E[i]*D[i]%mo+mo)%mo;
    ntt(D,0);

    for(int i=0;i<n;i++)
    E[i]=0;
    for(int i=x;i<n;i++)
    D[i]=0;
}

LL nn,aa[N];

int main()
{
    I[1]=Ijc[0]=jc[0]=1;
    for(int i=2;i<N;i++)
    I[i]=I[mo%i]*(mo-mo/i)%mo;

    for(int i=1;i<N;i++)
    jc[i]=jc[i-1]*i%mo,Ijc[i]=Ijc[i-1]*I[i]%mo;

    cin>>nn;
    for(int i=0;i<=nn;i++)
    scanf("%lld",&aa[i]),aa[i]=aa[i]*jc[i]%mo;
    printf("%lld ",aa[0]);

    for(int i=0;i<=nn+1;i++)
    B[i]=Ijc[i+1];

    init(nn+1);

    D[0]=1;
    ny(n);

    for(int i=nn+1;i<N;i++)
    D[i]=0;
    D[1]=499122177;

    mmcp(F,D);
    mmst(D,0);
    for(int i=0;i<=nn;i++)
    D[nn+1-i]=F[i];

    init(nn+nn+3);
    ntt(D,1);

    ntt(aa,1);
    for(int i=0;i<n;i++)
    D[i]=D[i]*aa[i]%mo;
    ntt(D,0);

    for(int i=1;i<=nn+1;i++)
    printf("%lld ",D[i+nn]*Ijc[i]%mo);
    cout<<endl;

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值