bzoj 4555 [Tjoi2016&Heoi2016]求和

http://www.elijahqi.win/archives/3137
Description

在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心。

现在他想计算这样一个函数的值:
这里写图片描述
S(i, j)表示第二类斯特林数,递推公式为:
S(i, j) = j ∗ S(i − 1, j) + S(i − 1, j − 1), 1 <= j <= i − 1。
边界条件为:S(i, i) = 1(0 <= i), S(i, 0) = 0(1 <= i)
你能帮帮他吗?
Input

输入只有一个正整数

Output

输出f(n)。由于结果会很大,输出f(n)对998244353(7 × 17 × 223 + 1)取模的结果即可。1 ≤ n ≤ 100000

Sample Input

3
Sample Output

87
HINT

Source

第二类斯特林数公式:
将n个物品放入m个无序的盒子中不允许为空 求方案数
Smn=1m!k=0m(1)kCkm(mk)n S n m = 1 m ! ∑ k = 0 m ( − 1 ) k C m k ∗ ( m − k ) n
首先将盒子有序 最后/(m!)
然后考虑容斥 表示从m个中钦定K个空的位置 然后剩下的随便放 这样的答案就是至少K个空位置的答案 那显然0个空位置是答案 那么就至少0-至少1+至少2 …这样就写出了这样一个通项公式
首先将斯特林数带入公式
Ans=i=0nj=0iSi,j×2j×(j!) A n s = ∑ i = 0 n ∑ j = 0 i S i , j × 2 j × ( j ! )
Ans=i=0nj=0j1j!k=0j(1)k×j!(jk)!×k!×(ik)i×2j×(j!) A n s = ∑ i = 0 n ∑ j = 0 j 1 j ! ∑ k = 0 j ( − 1 ) k × j ! ( j − k ) ! × k ! × ( i − k ) i × 2 j × ( j ! )
变换求和符号将其提到前面

Ans=j=0n(j!)×2jk=0j(1)k×1k!i=jn×(jk)i(jk)! A n s = ∑ j = 0 n ( j ! ) × 2 j ∑ k = 0 j ( − 1 ) k × 1 k ! ∑ i = j n × ( j − k ) i ( j − k ) !
所以可以设
ai=(1)ii! a i = ( − 1 ) i i !
bi=j=0niji! b i = ∑ j = 0 n i j i !
然后分别带入
Ans=j=0n(j!)×2jk=0ja[k]×b[jk] A n s = ∑ j = 0 n ( j ! ) × 2 j ∑ k = 0 j a [ k ] × b [ j − k ] 用ntt算一下后面的卷积其他预处理即可

#include<cstdio>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
const int gg=3;
const int N=1e5+10;
const int mod=998244353;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
inline int ksm(ll b,int t){static ll tmp;
    tmp=1;for (;t;b=b*b%mod,t>>=1)if (t&1) tmp=tmp*b%mod;return tmp;
}
ll g[N],inv[N];int mul[N],n,R[N<<2],a[N<<2],b[N<<2],invn,ans;
inline int inc(int x,int v){return x+v>=mod?x+v-mod:x+v;}
inline int dec(int x,int v){return x-v<0?x-v+mod:x-v;}
inline void ntt(int *x,int f){
    for (int i=0;i<n;++i) if (i<R[i]) swap(x[i],x[R[i]]);
    for (int i=1;i<n;i<<=1){
        ll wn=ksm(gg,f==1?(mod-1)/(i<<1):mod-1-(mod-1)/(i<<1));
        for (int j=0;j<n;j+=i<<1){
            ll w=1,t1,t2;
            for (int k=0;k<i;++k,w=w*wn%mod){
                t1=x[j+k],t2=w*x[i+j+k]%mod;
                x[j+k]=(t1+t2)%mod;x[i+j+k]=(t1-t2+mod)%mod;
            }
        }
    }
    if (f==-1) for (int i=0;i<n;++i) 
    x[i]=(ll)x[i]*invn%mod;
}
int main(){
    freopen("bzoj4555.in","r",stdin);
    n=read();g[0]=1;mul[0]=1;
    for (int i=1;i<=n;++i) g[i]=g[i-1]*i%mod,mul[i]=mul[i-1]*2%mod;
    inv[n]=ksm(g[n],mod-2);for (int i=n-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
    for (int i=0;i<=n;++i) a[i]=((i&1)?-1:1)*inv[i],
    b[i]=inv[i]*(i==1?(ll)n+1:(ll)(ksm(i,n+1)-1)*ksm(i-1,mod-2)%mod)%mod;
    int m=n<<1,nn=n,l=0;for (n=1;n<=m;n<<=1,++l);for (int i=0;i<n;++i) R[i]=(R[i>>1]>>1)|(i&1)<<l-1;
    invn=ksm(n,mod-2);ntt(a,1);ntt(b,1);
    for (int i=0;i<n;++i) a[i]=(ll)a[i]*b[i]%mod;ntt(a,-1);
    for (int i=0;i<=nn;++i) ans=inc(ans,g[i]*mul[i]%mod*a[i]%mod);printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值