1. 程式人生 > >CF 932E Team Work

CF 932E Team Work

原題題面

題目大意:求\(\sum\limits_{i=0}^{n}C_{n}^{i}i^{k}\)

我們根據套路\(n^{k}=\sum\limits_{i=0}^{k}C_{n}^{i}i!S_2(k,i)\)\(S_2\)表示第二類斯特林數。
\[ 原式=\displaystyle\sum_{i=0}^{n}C_{n}^{i}\sum_{j=0}^{k}C_{i}^{j}\cdot j!S_2(k,j)\\ =\sum_{i=0}^{n}C_n^i\sum_{j=0}^k C_i^jj!S_2(k,j) \]
因為\(k\)的規模遠小於\(n\)的規模,所以我們交換一下求和符號,在最外層列舉到\(k\)


\[ 原式=\displaystyle\sum_{j=0}^{k}S_2(k,j)j!\sum_{i=j}^{n} C_n^iC_i^j。 \]
這裡有一個結論:\(C_n^iC_i^j=C_n^jC_{n-i}^{j-i}。\\它的組合數意義是:先從n個數中取i個,再在那i個數中取j個;與先取j個,再在剩下的數中取i-j個。這兩個方案是等價的。\)

這樣,我們就得到了一個\(O(k)的式子:\displaystyle\sum_{j=0}^{k}S_2(k,j)j!C_n^j\sum_{i=j}^{n} C_{n-j}^{i-j}\)

計算\(C_n^j\)的時候可以計算\(n!*(n-1)!*...*(n-j+1)!再除以j!\)

然後\(\displaystyle\sum_{i=j}^{n} C_{n-j}^{i-j}=\sum_{d=0}^{n-j}C_{n-j}^d=2^{n-j}\)。於是這個問題就解決了。

程式碼:

#include<bits/stdc++.h>
#define ll long long

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

ll n,k;
ll fac[5005],inv[5005],suf[5005];
ll s[5005][5005];
const ll mod=1e9+7; 
ll ksm(ll t,ll x) {
    ll ans=1;
    for(;x;x>>=1,t=t*t%mod)
        if(x&1) ans=ans*t%mod;
    return ans;
}
ll C(int n,int m) {return fac[n]*ksm(fac[m]*fac[n-m]%mod,mod-2)%mod;}

ll cal(int n,int k) {
    if(!k) return 1;
    return suf[k-1]*inv[k]%mod;
}

int main() {
    n=Get(),k=Get();
    s[0][0]=1;
    for(int i=1;i<=k;i++)
        for(int j=1;j<=i;j++)
            s[i][j]=(s[i-1][j-1]+j*s[i-1][j])%mod;
    fac[0]=1;
    for(int i=1;i<=k;i++) fac[i]=fac[i-1]*i%mod;
    inv[k]=ksm(fac[k],mod-2);
    for(int i=k-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
    
    suf[0]=n;
    for(int i=1;i<=k;i++) suf[i]=suf[i-1]*(n-i)%mod;
    ll ans=0;
    int lim=min(n,k);
    for(int i=0;i<=lim;i++) {
        (ans+=s[k][i]*fac[i]%mod*cal(n,i)%mod*ksm(2,n-i)%mod)%=mod;
    }
    cout<<ans; 
    return 0;
}