Loading [MathJax]/extensions/TeX/mathchoice.js

BZOJ 4555: [Tjoi2016&Heoi2016]求和 第二类斯特林数+NTT

ni=0ij=0S(i,j)×2j×(j!)

不妨将式子化为 ni=0nj=0S(i,j)×2j×(j!) (反正如果 j>i 的话 S(i,j)=0)

其中 S(i,j) 为第二类斯特林数.

一般做这种推式子题时如果题面给的式子本身很简洁,那么八成是要把里面的东西暴力展开了.

展开斯特林数:S(n,m)=\frac{1}{m!}\sum_{i=0}^{m}(-1)^i\binom{m}{i}(m-i)^n

原式可化为 \sum_{i=0}^{n}\sum_{j=0}^{n}2^j(j!)\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{(j-k)^i}{(j-k)!}

考虑将 j 移到前面,得 \sum_{j=0}^{n}2^j(j!)\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{\sum_{i=0}^{n}(j-k)^i}{(j-k)!}

然后上面那个用等比数列求和公式处理,为 \sum_{j=0}^{n}2^j(j!)\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{(j-k)^{n+1}-1}{(j-k-1)(j-k)!}

后面那个是一个卷积的形式,用 NTT 加速即可(等比数列要特判一下公比为 1 的情况)

#include <bits/stdc++.h>   
#define G 3  
#define N 200001     
#define ll long long   
#define mod 998244353       
#define setIO(s) freopen(s".in","r",stdin)   
using namespace std;          
ll qpow(ll x,ll y) 
{
    ll tmp=1ll; 
    while(y)  
    { 
        if(y&1)  tmp=tmp*x%mod; 
        x=x*x%mod, y>>=1;  
    }  
    return tmp;   
}   
ll Inv(ll x)  { return qpow(x,mod-2);  }   
void NTT(ll *a,int len,int op) 
{
    int i,j,mid,k;   
    for(i=k=0;i<len;++i) 
    {
        if(i>k)   swap(a[i],a[k]);   
        for(j=len>>1;(k^=j)<j;j>>=1);   
    }    
    for(mid=1;mid<len;mid<<=1) 
    {
        ll wn=qpow(G,(mod-1)/(mid<<1)); 
        if(op==-1)   wn=Inv(wn);  
        for(i=0;i<len;i+=mid<<1) 
        { 
            ll w=1ll;    
            for(j=0;j<mid;++j) 
            {
                ll x=a[i+j],y=w*a[i+j+mid]%mod;     
                a[i+j]=(x+y)%mod, a[i+j+mid]=(x-y+mod)%mod;     
                w=w*wn%mod;     
            }
        }
    } 
    if(op==-1) 
    {
        ll rev=Inv(len); 
        for(i=0;i<len;++i)   a[i]=a[i]*rev%mod;         
    }
}       
ll fac[N],inv[N],f[N<<1],g[N<<1];        
int main() 
{ 
    // setIO("input");  
    int i,j,n,limit;   
    scanf("%d",&n);        
    fac[0]=inv[0]=1ll; 
    for(i=1;i<N;++i)    fac[i]=fac[i-1]*1ll*i%mod,   inv[i]=Inv(fac[i]);   
    f[0]=1ll, g[0]=1ll, g[1]=n+1;    
    for(i=1;i<=n;++i)   f[i]=(qpow(-1,i)*inv[i]+mod)%mod;   
    for(i=2;i<=n;++i)   g[i]=(qpow(i,n+1)-1+mod)%mod*inv[i]%mod*Inv(i-1)%mod;       
    for(limit=1;limit<=2*n;limit<<=1);          
    NTT(f,limit,1),  NTT(g,limit,1);                   
    for(i=0;i<limit;++i)    f[i]=f[i]*g[i]%mod;   
    NTT(f,limit,-1);    
    ll ans=0ll;   
    for(i=0;i<=n;++i)    (ans+=qpow(2,i)*fac[i]%mod*f[i]%mod)%=mod;       
    printf("%lld\n",ans);   
    return 0; 
}   
posted @   EM-LGH  阅读(118)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示