1. 程式人生 > >[HEOI2016/TJOI2016]求和——第二類斯特林數

[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 */