码迷,mamicode.com
首页 > 其他好文 > 详细

[HEOI2016/TJOI2016]求和

时间:2018-07-16 21:05:18      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:getchar   data   type   turn   cst   cstring   strong   stream   span   

description

题面

给定\(n\),求\[f(n)=\sum_{i=0}^n\sum_{j=0}^i S(i,j)\times 2^j \times (j!)\]

data range

\[1≤n≤100000\]

solution

第二类斯特林数及其递推式和展开式

\(S(n,m)\)表示把\(n\)个有差别的球放入\(m\)个无差别的盒子中且无一空盒的方案数,递推式为

\[S(n,m)=mS(n?1,m)+S(n?1,m?1),1≤m≤n?1\]

边界条件为:\(S(n,n)=1(0≤n),S(n,0)=0(1≤n)\)

由容斥原理得其展开式为

\[S(n,m)=\frac{1}{m!}\sum_{i=0}^{m}(-1)^iC_m^i(m-i)^n\]

考虑到\(i<j\)时,\(S(i,j)=0\)于是原式化为

\[f(n)=\sum_{i=0}^n\sum_{j=0}^n\sum_{k=0}^{j}(-1)^kC_j^k2^j(j-k)^i\]

千辛万苦得到了

\[\sum_{j=0}^n2^jj!\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{\sum_{i=0}^{n}(j-k)^i}{(j-k)!}\]

不知道\(\sum_{i=0}^{n}(j-k)^i\)怎么算?
等比数列啊!!!\(\sum_{i=0}^{n}(j-k)^i=\frac{(j-k)^{n+1}-1}{j-k-1}\)

于是我们得到了最后的递推式

\[\sum_{j=0}^n2^jj!\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{(j-k)^{n+1}-1}{(j-k-1)(j-k)!}\]

继续\(NTT\)

code

注意\(g(0)=1,g(1)=n+1\)

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=998244353;
const int N=1000010;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INF=1e18+1;
il ll read(){
    RG ll data=0,w=1;RG char ch=getchar();
    while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar();
    if(ch==‘-‘)w=-1,ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)data=data*10+ch-48,ch=getchar();
    return data*w;
}

il void file(){
    srand(time(NULL)+rand());
    freopen(FILE".in","r",stdin);
    freopen(FILE".out","w",stdout);
}

il int poww(int a,int b){
    RG int ret=1;
    for(;b;b>>=1,a=1ll*a*a%mod)
        if(b&1)ret=1ll*ret*a%mod;
    return ret;
}

int l,r[N];
il void NTT(int *a,int n,int opt){
    for(l=0;(1<<l)<n;l++);n=(1<<l);
    for(RG int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    for(RG int i=0;i<n;i++)if(i<r[i])swap(a[i],a[r[i]]);
    for(RG int i=2;i<=n;i<<=1){
        RG int wn=poww(opt==1?3:(mod+1)/3,(mod-1)/i);
        for(RG int j=0;j<n;j+=i){
            RG int w=1;
            for(RG int k=j;k<j+(i>>1);k++,w=1ll*w*wn%mod){
                RG int x=1ll*a[k+(i>>1)]*w%mod;
                a[k+(i>>1)]=(a[k]-x+mod)%mod;
                a[k]=(a[k]+x)%mod;
            }       
        }
    }
    if(opt==-1)
        for(RG int i=0,rv=poww(n,mod-2);i<n;i++)
            a[i]=1ll*a[i]*rv%mod;
}

int n,m,f[N],g[N],len,ans;
int pw[N],fac[N],inv[N];
il void init(){
    pw[0]=fac[0]=inv[0]=1;
    for(RG int i=1;i<=n;i++)
        pw[i]=1ll*pw[i-1]*2%mod,fac[i]=1ll*fac[i-1]*i%mod;
    inv[n]=poww(fac[n],mod-2);
    for(RG int i=n-1;i;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
}

int main()
{
    n=read();init();g[0]=1;g[1]=n+1;
    for(RG int i=0;i<=n;i++)f[i]=1ll*((i&1)?(mod-1):1)*inv[i]%mod;
    for(RG int i=2;i<=n;i++)
        g[i]=1ll*(poww(i,n+1)+mod-1)%mod*poww(i-1,mod-2)%mod*inv[i]%mod;
    for(len=1;len<=(n<<1);len<<=1);
    NTT(f,len,1);NTT(g,len,1);
    for(RG int i=0;i<len;i++)f[i]=1ll*f[i]*g[i]%mod;
    NTT(f,len,-1);
    for(RG int i=0;i<=n;i++)(ans+=1ll*f[i]*pw[i]%mod*fac[i]%mod)%=mod;
    printf("%d\n",ans);return 0;
}

[HEOI2016/TJOI2016]求和

标签:getchar   data   type   turn   cst   cstring   strong   stream   span   

原文地址:https://www.cnblogs.com/cjfdf/p/9319968.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!