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

    题目

    [sum_{i=0}^nsum_{j=0}^iS_2(i,j)2^jj! ]

    (S_2(i,j))为第二类斯特林数

    这什么神仙操作,这种东西能求?

    慢慢来做

    首先想到二类斯特林的组合意义,就是把(i)个球放到(j)个盒子里且不允许有空

    我们容斥一波,发现

    [S_2(i,j)=frac{1}{j!}sum_{k=0}(-1)^kinom{j}{k}(j-k)^i ]

    这个的意思就是强行枚举有(k)个盒子什么都不能选,这样就是组合数(inom{j}{k}),之后剩下的(i)个小球每个都会有(j-k)种选择,就是((j-k)^i),这样算出来的是至少有(k)个空盒子的方案,我们容斥一下就有了那个容斥系数

    至于为什么容斥系数是((-1)^k)

    让我们来证明一下

    上面那个柿子的含义显然是至少有(k)个空盒子,那么我们来考虑一下如果有(n)个空盒子会被算到多少次

    显然是

    [sum_{i=0}^ninom{n}{i}(-1)^i ]

    显然在(n>=1)的情况下我们可以直接使用二项式定理把这个柿子改写成((1-1)^n=0),在(n=0)的时候这个柿子的值却是(1)

    但是我们组合数是使盒子产生了差别,于是外面除以(j!)消除这个差别

    还发现(j>i)的时候,(S_2(i,j)=0),我们可以考虑把(j)的上标改写成(n)

    于是我们可以把柿子写成

    [sum_{i=0}^nsum_{j=0}^nsum_{k=0}^jfrac{1}{j!}(-1)^kinom{j}{k}(j-k)^i2^jj! ]

    我们优先展开组合数

    [sum_{i=0}^nsum_{j=0}^n2^jj!sum_{k=0}^jfrac{(-1)^kj!(j-k)^i}{j!(j-k)!k!} ]

    发现分子分母都有(j!),于是约去

    [sum_{i=0}^nsum_{j=0}^n2^jj!sum_{k=0}^jfrac{(-1)^k}{k!} imes frac{(j-k)^i}{(j-k)!} ]

    发现里面开始有点像卷积的形式了,开始喜闻乐见交换求和符号

    [sum_{j=0}^n2^jj!sum_{k=0}^jfrac{(-1)^k}{k!}sum_{i=0}^nfrac{(j-k)^i}{(j-k)!} ]

    (k+j-k)可是等于(j)的我们终于看到卷积形式了

    于是搞两个多项式

    [F_i=frac{(-1)^i}{i!},G_i=frac{sum_{j=0}^ni^j}{i!}=frac{frac{i^{n+1}-1}{i-1}}{i!}=frac{i^{n+1}-1}{i!(i-1)} ]

    这两个多项式一卷就是答案了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=262144+10005;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,len,rev[maxn];
    LL inv[maxn],fac[maxn],A[maxn],B[maxn];
    const LL G[2]={3,332748118};
    const LL mod=998244353;
    inline LL quick(LL a,LL b) {LL S=1;while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;}
    inline void NTT(LL *f,int o) {
    	for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
    	for(re int i=2;i<=len;i<<=1) {
    		int ln=i>>1;LL og1=quick(G[o],(mod-1)/i);
    		for(re int l=0;l<len;l+=i) {
    			LL t,og=1;
    			for(re int x=l;x<l+ln;x++) {
    				t=(f[ln+x]*og)%mod;
    				f[ln+x]=(f[x]-t+mod)%mod;
    				f[x]=(f[x]+t)%mod;
    				og=(og*og1)%mod;
    			}
    		}
    	}
    	if(!o) return;
    	LL Inv=quick(len,mod-2);
    	for(re int i=0;i<len;i++) f[i]=(f[i]*Inv)%mod; 
    }
    int main() {
    	n=read();
    	fac[0]=1;
    	for(re int i=1;i<=n;i++) fac[i]=(fac[i-1]*(LL)i)%mod;
    	inv[n]=quick(fac[n],mod-2);
    	for(re int i=n-1;i>=0;--i) inv[i]=(inv[i+1]*(LL)(i+1))%mod;
    	for(re int i=0;i<=n;i++) if(i&1) A[i]=mod-inv[i];else A[i]=inv[i];
    	B[0]=1,B[1]=n+1;
    	for(re int i=2;i<=n;i++) 
    		B[i]=(quick(i,n+1)-1)*inv[i]%mod*quick(i-1,mod-2);
    	len=1;
    	while(len<n+n) len<<=1;
    	for(re int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?len>>1:0);
    	NTT(A,0),NTT(B,0);
    	for(re int i=0;i<len;i++) A[i]=(A[i]*B[i])%mod;
    	NTT(A,1);
    	LL ans=0,pow=1;
    	for(re int i=0;i<=n;i++) {
    		ans+=A[i]*fac[i]%mod*pow%mod;
    		ans%=mod,pow=(pow*2ll)%mod;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    我不喜欢的 Rust 特性 (之一) eager drop
    为 Windows Phone 8.1 app 解决“The type does not support direct content.”的问题
    输入10个互不相同的数字并分成5对,问有多少种分法。
    code wars quiz: toInteger
    my first emacs custom key binding
    http协议消息报头学习笔记
    移动端经常遇到的小bug
    js小技巧
    ajax
    js正则表达
  • 原文地址:https://www.cnblogs.com/asuldb/p/10544302.html
Copyright © 2011-2022 走看看