[HEOI2016/TJOI2016]求和——第二类斯特林数

给你斯特林数就换成通项公式,给你k次方就换成斯特林数

考虑换成通项公式之后,组合数没有什么好的处理方法

直接拆开,消一消阶乘

然后就发现了(j-k)和k!

往NTT方向靠拢

然后大功告成

其实只要想到把斯特林公式换成通项公式,考虑用NTT优化掉(j-k)^i

后面都是套路了。

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define int long long
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=100000+5;
const int mod=998244353;
const int G=3;
const int GI=332748118;
ll qm(ll x,ll y){
    ll ret=1;
    while(y){
        if(y&1) ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }return ret;
}
int rev[4*N];
ll a[4*N],b[4*N];
int n;
void NTT(ll *f,int c){
    for(reg i=0;i<n;++i){
        if(rev[i]<i) swap(f[i],f[rev[i]]);
    }
    for(reg p=2;p<=n;p<<=1){
        ll gen;
        if(c==1) gen=qm(G,(mod-1)/p);
        else gen=qm(GI,(mod-1)/p);
        int len=p/2;
        for(reg l=0;l<n;l+=p){
            ll buf=1;
            for(reg k=l;k<l+len;++k){
                ll tmp=f[k+len]*buf%mod;
                f[k+len]=(f[k]-tmp+mod)%mod;
                f[k]=(f[k]+tmp)%mod;
                buf=buf*gen%mod;
            }
        }
    }
}
ll jie[N],inv[N],ni[N];
int main(){
    rd(n);jie[0]=1;
    for(reg i=1;i<=n;++i) jie[i]=jie[i-1]*i%mod;
    inv[n]=qm(jie[n],mod-2);inv[0]=1;
    for(reg i=n-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod;
    for(reg i=1;i<=n;++i) ni[i]=((mod-mod/i)*ni[mod%i]+mod)%mod;
    for(reg i=0;i<=n;++i){
        if(i&1) a[i]=mod-inv[i];
        else a[i]=inv[i];
        if(i==1) b[i]=n+1;
        else if(i==0) b[i]=1;
        else b[i]=(qm(i,n+1)-1+mod)%mod*qm(i-1,mod-2)%mod*inv[i]%mod;
    }
    int m;
    int lp=n;
    for(m=n+n,n=1;n<=m;n<<=1);
    for(reg i=0;i<n;++i){
        rev[i]=(rev[i>>1]>>1)|((i&1)?n>>1:0);
    }
//    for(reg i=0;i<n;++i){
//        cout<<a[i]<<" ";
//    }cout<<endl;
//    for(reg i=0;i<n;++i){
//        cout<<b[i]<<" ";
//    }cout<<endl;
    
    NTT(a,1);NTT(b,1);
    for(reg i=0;i<n;++i) b[i]=(ll)b[i]*a[i]%mod;
    NTT(b,-1);ll yuan=qm(n,mod-2);
    for(reg i=0;i<n;++i) b[i]=b[i]*yuan%mod;
    ll ans=0;
    for(reg j=0;j<=lp;++j){
       // cout<<" bj "<<j<<" : "<<b[j]<<endl;
        ans=(ans+qm(2,j)*jie[j]%mod*b[j]%mod)%mod;
        //cout<<" ans "<<ans<<endl;
    }
    printf("%lld",ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/12/28 21:51:13
*/

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10197836.html