zoukankan      html  css  js  c++  java
  • [HEOI2016/TJOI2016]求和

    Discription

    在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

       我们知道第二类斯特林数和排列数(下降幂)组合在一起可以表示n^k,又因为排列等于组合乘上一个阶乘,于是我们就可以开开心心的二项式反演,得到一个某一行(其实也可以很多行,鉴于这个式子的特殊性质,我们可以把不同行的同一列合并)某一列的斯特林数的表达式。

        具体的说,S(k,n) = Σ (i^k / i!) * ((-1)^(n-i) / (n-i)!)     [具体推导就不写了,就是一个二项式反演]。

    这个式子的特殊性质太多了,首先它是一个卷积的形式,所以我们可以直接用NTT 在 N log N 的时间求出某一行的所有第二类斯特林数分别是多少;

    并且只有 i^k 项和行数有关,所以同一列很好合并,于是这个题就做完了2333。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=330005;
    const int ha=998244353;
    const int root=3,inv=ha/3+1;
    int a[maxn],b[maxn],jc[maxn];
    int r[maxn],N,M,n,INV,l;
    
    inline int add(int x,int y){
    	x+=y;
    	return x>=ha?x-ha:x;
    }
    
    inline int ksm(int x,int y){
    	int an=1;
    	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
    	return an;
    }
    
    inline void NTT(int *c,const int f){
    	for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]);
    	
    	for(int i=1;i<N;i<<=1){
    		int omega=ksm(f==1?root:inv,(ha-1)/(i<<1));
    		for(int p=i<<1,j=0;j<N;j+=p){
    			int now=1;
    			for(int k=0;k<i;k++,now=now*(ll)omega%ha){
    				int x=c[j+k],y=c[j+k+i]*(ll)now%ha;
    				c[j+k]=add(x,y);
    				c[j+k+i]=add(x,ha-y);
    			}
    		}
    	}
    	
    	if(f==-1) for(int i=0;i<N;i++) c[i]=c[i]*(ll)INV%ha;
    }
    
    inline void init(){
    	jc[0]=1;
    	for(int i=1;i<=n;i++) jc[i]=jc[i-1]*(ll)i%ha;
    	for(int i=0;i<=n;i++){
    		if(!i) a[i]=1;
    		else if(i==1) a[i]=n+1;
    		else a[i]=add(ksm(i,n+1),ha-1)*(ll)ksm(add(i,ha-1)*(ll)jc[i]%ha,ha-2)%ha;
    		if(i&1) b[i]=ha-ksm(jc[i],ha-2);
    		else b[i]=ksm(jc[i],ha-2);
    	}
    	
    	M=n<<1;
    	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));
    }
    
    inline void solve(){
    	NTT(a,1),NTT(b,1);
    	for(int i=0;i<N;i++) a[i]=a[i]*(ll)b[i]%ha;
    	INV=ksm(N,ha-2),NTT(a,-1);
    }
    
    inline void output(){
    	int ans=0,base=1;
    	for(int i=0;i<=n;i++,base=add(base,base)) ans=add(ans,a[i]*(ll)base%ha*(ll)jc[i]%ha);
    	printf("%d
    ",ans);
    }
    
    int main(){
    	scanf("%d",&n);
    	init();
    	solve();
    	output();
    	return 0;
    }
    

      

  • 相关阅读:
    FMDB线程安全
    FMDB的使用
    iOS【手机验证码】判断手机号是否合法
    UIScrollView UIScrollViewDelegate
    iOS苹果开发者常用网站
    < meta http-equiv = "X-UA-Compatible" content = "IE=edge,chrome=1" />
    CSS布局口诀
    css垂直居中
    在js中使用createElement创建HTML对象和元素
    jQuery-对Radio/CheckBox的操作集合
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8640895.html
Copyright © 2011-2022 走看看