1. 程式人生 > >[CF932E]Team Work & [BZOJ5093]圖的價值

[CF932E]Team Work & [BZOJ5093]圖的價值

%d 放置 swap online 至少 while urn 組合 ems

CF題面
題意:求\(\sum_{i=0}^{n}\binom{n}{i}i^k\)
\(n\le10^9,k\le5000\)
\(10^9+7\)
BZOJ題面
題意:求\(n*2^{\frac{n(n-1))}{2}-(n-1)}*\sum_{i=0}^{n-1}\binom{n-1}{i}i^k\)
\(n\le10^9,k\le2*10^5\)
\(998244353\)

第二類斯特林數

趕緊去學第二類斯特林數啊
第二類斯特林數:\(S(n,m)\),表示把\(n\)個不同的的球放到\(m\)個相同的盒子且不允許空盒的方案數。
首先有一個\(O(n^2)\)的遞推。考慮第\(n\)個球的放置,如果單獨放置方案數就等於\(S(n-1,m-1)\)

,否則就是\(m*S(n-1,m)\),表示枚舉放在那個盒子裏。寫出來就是
\[S(n,m)=S(n-1,m-1)+m*S(n-1,m)\]
邊界條件:\(S(0,0)=1,S(i,0)=0(i>0)\)
然後還有各種考慮組和意義得出來的柿子
第二類斯特林數存在通項公式。因為\(m^n\)表示把\(n\)個不同的球放到\(m\)個不同的盒子裏且允許空盒的方案數,我們想辦法用這個東西構造出第二類斯特林數的組和意義。
首先盒子是否相同很好辦,直接乘/除以\(m!\)即可。關鍵問題在於空盒的處理。
考慮容斥,計算“至少有\(k\)個空盒然後剩下的隨便是不是空盒的方案數”,乘上一個容斥系數
\[S(n,m)=\frac{1}{m!}\sum_{k=0}^{m}(-1)^k\binom{m}{k}(m-k)^n\]

還有一個,反過來用第二類斯特林數來表示\(m^n\)
其實就是一個反演,但如果也同樣考慮組和意義的話豈不妙哉。
枚舉有幾個盒子不是空的,可以直接得到如下柿子:
\[m^n=\sum_{i=0}^{m}S(n,i)*\binom{m}{i}*i!\]

sol

所以說這道題怎麽做呢?
開始推柿子辣~
\[\sum_{i=0}^{n}\binom{n}{i}i^k=\sum_{i=0}^{n}\binom{n}{i}\sum_{j=0}^{i}S(k,j)*\binom{i}{j}*j!\\=\sum_{j=0}^{n}S(k,j)*j!\sum_{i=j}^{n}\binom{n}{i}\binom{i}{j}\\=\sum_{j=0}^{n}S (k,j)*j!*\binom{n}{j}*2^{n-j}\\=\sum_{j=0}^{k}S (k,j)*j!*\binom{n}{j}*2^{n-j}\]


柿子裏面的階乘\(j!\)、組合數\(\binom{n}{j}\)、2的次冪\(2^{n-j}\)都可以\(O(k)\)處理出來。復雜度瓶頸在於第二類斯特林數的處理。
\(k\le5000\)可以直接用遞推式\(O(k^2)\)處理出來,而觀察其通項式會發現其實就是一個卷積形式:
\[S(n,m)=\frac{1}{m!}\sum_{k=0}^{m}(-1)^k\binom{m}{k}(m-k)^n\\=\sum_{k=0}^{m}\frac{(-1)^k}{k!}*\frac{(m-k)^n}{(m-k)!}\]
所以直接上\(NTT\),復雜度\(O(k\log{k})\)
但是\(CF\)上的那道題不能用\(NTT\)誒,畢竟\(10^9+7\)怎麽\(NTT\)

code

[CF932E]Team Work
這裏我強行用通項公式然後寫了個\(O(k^2)\)的多項式乘法

#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 1e9+7;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
int fastpow(int a,int b)
{
    int res=1;
    while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    return res;
}
const int N = 5005;
int jc[N],C[N],two[N],inv,a[N],b[N],s[N],ans;
int main()
{
    int n=gi(),k=gi();
    jc[0]=1;
    for (int i=1;i<=k;++i) jc[i]=1ll*jc[i-1]*i%mod;
    C[0]=1;
    for (int i=1;i<=k;++i) C[i]=1ll*C[i-1]*(n-i+1)%mod*fastpow(i,mod-2)%mod;
    two[0]=fastpow(2,n);inv=fastpow(2,mod-2);
    for (int i=1;i<=k;++i) two[i]=1ll*two[i-1]*inv%mod;
    for (int i=0;i<=k;++i) a[i]=i&1?mod-fastpow(jc[i],mod-2):fastpow(jc[i],mod-2);
    for (int i=0;i<=k;++i) b[i]=1ll*fastpow(i,k)*fastpow(jc[i],mod-2)%mod;
    for (int i=0;i<=k;++i)
        for (int j=0;j<=i;++j)
            (s[i]+=1ll*a[j]*b[i-j]%mod)%=mod;
    for (int i=1;i<=k;++i) (ans+=1ll*s[i]*jc[i]%mod*C[i]%mod*two[i]%mod)%=mod;
    printf("%d\n",ans);
    return 0;
}

[BZOJ5093]圖的價值

#include<cstdio>
#include<algorithm>
using namespace std;
const int _ = 800005;
const int mod = 998244353;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
int fastpow(int a,int b)
{
    int res=1;
    while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    return res;
}
int n,N,k,l;
int jc[_],C[_],two[_],inv,a[_],b[_],rev[_],ans;
void NTT(int *P,int opt)
{
    for (int i=0;i<N;++i) if (i>rev[i]) swap(P[i],P[rev[i]]);
    for (int i=1;i<N;i<<=1)
    {
        int W=fastpow(3,(mod-1)/(i<<1));
        if (opt==-1) W=fastpow(W,mod-2);
        for (int j=0,p=i<<1;j<N;j+=p)
        {
            int w=1;
            for (int k=0;k<i;++k,w=1ll*w*W%mod)
            {
                int x=P[j+k],y=1ll*P[j+k+i]*w%mod;
                P[j+k]=(x+y)%mod;P[j+k+i]=(x-y+mod)%mod;
            }
        }
    }
    if (opt==-1)
    {
        int Inv=fastpow(N,mod-2);
        for (int i=0;i<N;++i) P[i]=1ll*P[i]*Inv%mod;
    }
}
int main()
{
    n=gi()-1;k=gi();
    jc[0]=1;
    for (int i=1;i<=k;++i) jc[i]=1ll*jc[i-1]*i%mod;
    C[0]=1;
    for (int i=1;i<=k;++i) C[i]=1ll*C[i-1]*(n-i+1)%mod*fastpow(i,mod-2)%mod;
    two[0]=fastpow(2,n);inv=fastpow(2,mod-2);
    for (int i=1;i<=k;++i) two[i]=1ll*two[i-1]*inv%mod;
    for (int i=0;i<=k;++i) a[i]=i&1?mod-fastpow(jc[i],mod-2):fastpow(jc[i],mod-2);
    for (int i=0;i<=k;++i) b[i]=1ll*fastpow(i,k)*fastpow(jc[i],mod-2)%mod;
    for (N=1;N<=k*2;N<<=1) ++l;--l;
    for (int i=0;i<N;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
    NTT(a,1);NTT(b,1);
    for (int i=0;i<N;++i) a[i]=1ll*a[i]*b[i]%mod;
    NTT(a,-1);
    for (int i=0;i<=k;++i) (ans+=1ll*a[i]*jc[i]%mod*C[i]%mod*two[i]%mod)%=mod;
    int Pow=(1ll*n*(n+1)/2-n)%(mod-1);
    printf("%d\n",1ll*ans*fastpow(2,Pow)%mod*(n+1)%mod);
    return 0;
}

[CF932E]Team Work & [BZOJ5093]圖的價值