loj2058 「TJOI / HEOI2016」求和 NTT

loj2058 「TJOI / HEOI2016」求和 NTT

链接

loj

思路

\[S(i,j)=\frac{1}{j!}\sum\limits_{k=0}^{j}(-1)^{k}C_{j}^{k}(j-k)^{i}\]
\[\sum\limits_{i=0}^{n}\sum\limits_{j=0}^{i}S(i,j)·2^j·j!\]
\[\sum\limits_{i=0}^{n}\sum\limits_{j=0}^{n}S(i,j)·2^j·j!\]
\[\sum\limits_{j=0}^{n}2^j·j!\sum\limits_{i=0}^{n}S(i,j)\]
先看后边
\[\sum\limits_{i=0}^{n}\frac{1}{j!}\sum\limits_{k=0}^{j}(-1)^{k}C_{j}^{k}(j-k)^{i}\]
\[\frac{1}{j!}\sum\limits_{k=0}^{j}(-1)^{k}C_{j}^{k}\sum\limits_{i=0}^{n}(j-k)^{i}\]
\[\sum\limits_{k=0}^{j}(-1)^{k}\frac{1}{k!(j-k)!}\sum\limits_{i=0}^{n}(j-k)^{i}\]
\(f(j-k)=\sum\limits_{i=0}^{n}(j-k)^{i}\)等比数列求和。
\[\sum\limits_{k=0}^{j}\frac{(-1)^{k}}{k!}\frac{f(j-k)}{(j-k)!}\]
nice,这很卷积,用NTT预处理就好了,然后后面的式子就很好求ans了。
$\(\sum\limits_{j=0}^{n}2^j·j!\sum\limits_{k=0}^{j}\frac{(-1)^{k}}{k!}\frac{f(j-k)}{(j-k)!}\)

坑点

f(x)要特判q=1和q=0。因为公式本来就不能做
其他的照的推出来的式子做就可以辣

代码

#include <bits/stdc++.h>
using namespace std;
const int N=4e5+7,mod=998244353;
int n,ans,jc[N],a[N],b[N],limit=1,p,r[N];
int q_pow(int a,int b) {
    int ans=1;
    while(b) {
        if(b&1) ans=1LL*a*ans%mod;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return ans;
}
int inv(int a) {return q_pow(a,mod-2);}
int ntt(int *a,int type) {
    for(int i=0;i<limit;++i)
        if(i<r[i]) swap(a[i],a[r[i]]);
    for(int mid=1;mid<limit;mid<<=1) {
        int Wn=q_pow(3,(mod-1)/(mid<<1));
        for(int i=0;i<limit;i+=(mid<<1)) {
            for(int j=0,w=1;j<mid;j++,w=1LL*w*Wn%mod) {
                int x=a[i+j],y=1LL*w*a[i+j+mid]%mod;
                a[i+j]=(x+y)%mod;
                a[i+j+mid]=(x-y+mod)%mod;
            }
        }
    }
    if(type==-1) {
        reverse(&a[1],&a[limit]);
        int inv=q_pow(limit,mod-2);
        for(int i=0;i<limit;++i) a[i]=1LL*a[i]*inv%mod;
    }
}
int f(int x) {
    if(!x) return 1;
    if(x==1) return n+1;
    return 1LL*(q_pow(x,n+1)-1)*inv(x-1)%mod;
}
int main() {
    scanf("%d",&n);
    jc[0]=1;for(int i=1;i<=n;++i) jc[i]=1LL*jc[i-1]*i%mod;
    for(int i=0;i<=n;++i) a[i]=1LL*(i&1?(mod-1):1)*inv(jc[i])%mod;
    for(int i=0;i<=n;++i) b[i]=1LL*f(i)*inv(jc[i])%mod;
        
    while(limit<n+n) limit<<=1,p++;
    for(int i=0;i<limit;++i)
        r[i]=(r[i>>1]>>1)|((i&1)<<(p-1));
    ntt(a,1),ntt(b,1);
    for(int i=0;i<limit;++i) a[i]=1LL*a[i]*b[i]%mod;
    ntt(a,-1);
    
    for(int i=0;i<=n;++i) 
        ans=(ans+1LL*q_pow(2,i)*jc[i]%mod*a[i]%mod)%mod;
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/dsrdsr/p/11214667.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值