1. 程式人生 > 其它 >21.6.29 t3

21.6.29 t3

tag:minmax反演,指數型生成函式,概率期望


屑模擬賽放原題

【集訓隊作業2018】喂鴿子


如果寫出操作序列,設 \(a_{i,j}\) 表示 \(i\)\(j\) 次出現是在 \(a_{i,j}\) 位置。

那麼題目要求的就是 \(\max a_{i,k}\)

運用minmax反演

\[ans=\sum_{S\subseteq\{1\cdots n\},S\not=\varnothing}(-1)^{|S|+1}\min(S) \]

也就是列舉一個集合,求這個集合中任意一個物品出現 \(k\) 次的期望步數。

這樣就可以列舉所有可能的序列長度了(原問題可以是無窮序列)


對於長度為 \(len\)

的操作序列,先選出 \(\max\) 元素和它的位置 \(|S|\cdot\binom{len-1}{k-1}\)(因為最後一個一定是 \(\max\) 元素)。

然後問題變為,\(|S|\) 個物品放到長度為 \(len-k\) 的序列中,每個物品不能出現超過 \(k-1\) 次。

這個也就是

\[[x^{len-k}](\sum_{i=0}^{k-1}\frac{x^i}{i!})^{|S|-1} \]

可以在最開始預處理出來,用fft複雜度為 \(O(nklog(nk))\)

然後還要注意考慮集合外元素的貢獻(根據 \(a_{i,j}\) 的定義,不能只考慮 \(S\) 中的元素)

問題變為 \(a\)

個黑球,\(b\) 個 白球,每次隨機拿出一個並放回,求期望多少次拿出第一個白球。

這個是概率期望經典問題,期望就是概率的倒數 \(\frac {a+b}b\)。(實在想不明白可以暴力等比數列求和)

相當於期望步長為 \(\frac n{|S|}\),直接乘上就行。

然後還要乘上每個序列的出現概率,\((\frac 1{|S|})^{len}\)


然後注意到 \(S\) 的貢獻只與大小有關,所以改為列舉大小就行了。

\[ans=\sum_{|S|=1}^n\binom n{|S|}\sum_{len=k}^{|S|(k-1)+1}([x^{len-k}](\sum_{i=0}^{k-1}\frac{x^i}{i!})^{|S|-1}\cdot |S|\cdot\binom{len-1}{k-1}\cdot (\frac 1{|S|})^{len}\cdot len\cdot \frac n{|S|}) \]

複雜度 \(O(nklog(nk)-n^2k)\)

,不知道為什麼資料範圍這麼小。。

#include<bits/stdc++.h>
using namespace std;
 
template<typename T>
inline void Read(T &n){
    char ch; bool flag=false;
    while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
    for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
    if(flag)n=-n;
}
 
enum{
    MAXN = 50005,
    MOD = 998244353
};
 
inline int ksm(int base, int k=MOD-2){
    int res=1;
    while(k){
        if(k&1)
            res = 1ll*res*base%MOD;
        base = 1ll*base*base%MOD;
        k >>= 1;
    }
    return res;
}
 
inline long long kspow(long long base, long long k){
    long long res=1;
    while(k){
        if(k&1)
            res *= base;
        base *= base;
        k >>= 1;
    }
    return res;
}
 
inline int inc(int a, int b){
    a += b;
    if(a>=MOD) a -= MOD;
    return a;
}
 
inline int dec(int a, int b){
    a -= b;
    if(a<0) a += MOD;
    return a;
}
 
inline void iinc(int &a, int b){a = inc(a,b);}
inline void ddec(int &a, int b){a = dec(a,b);}
inline void upd(int &a, long long b){a = (a+b)%MOD;}
 
namespace FFT{
    int f[MAXN<<2], g[MAXN<<2], wn[MAXN<<2], tr[MAXN<<2];
     
    inline int prework(int n){
        int len=1; while(len<=n) len<<=1;
        for(int i=0; i<len; i++) tr[i] = (tr[i>>1]>>1)|((i&1)?len>>1:0);
        wn[0] = 1; wn[1] = ksm(3,(MOD-1)/len);
        for(int i=2; i<=len; i++) wn[i] = 1ll*wn[i-1]*wn[1]%MOD;
        return len;
    }
     
    inline void fft(int *f, int n, int flag){
        for(int i=0; i<n; i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
        for(int len=2; len<=n; len<<=1){
            int base = n/len*flag;
            for(int l=0; l<n; l+=len){
                int now = (flag==1?0:n);
                for(int i=l; i<l+len/2; i++){
                    int tmp = 1ll*f[i+len/2]*wn[now]%MOD;
                    f[i+len/2] = dec(f[i],tmp);
                    iinc(f[i],tmp);
                    now += base;
                }
            }
        }
        if(flag==-1){
            int invn = ksm(n);
            for(int i=0; i<n; i++) f[i] = 1ll*f[i]*invn%MOD;
        }
    }
}
using FFT::fft;
using FFT::prework;
 
int n, k, tp, jc[MAXN], invjc[MAXN], inv[51], f[51][MAXN];
int pw[51][MAXN];
 
inline void mul(int pos){
    for(int i=0; i<=(pos-1)*k; i++) FFT::f[i] = f[pos-1][i];
    fft(FFT::f,tp,1);
    for(int i=0; i<tp; i++) f[pos][i] = 1ll*FFT::f[i]*FFT::g[i]%MOD;
    fft(f[pos],tp,-1);
    fill(FFT::f,FFT::f+tp,0);
}
 
inline int C(int n, int m){return 1ll*jc[n]*invjc[m]%MOD*invjc[n-m]%MOD;}
 
int main(){
    Read(n); Read(k);
    f[0][0] = 1; invjc[0] = jc[0] = 1; tp = prework((n-1)*(k-1));
    for(int i=1; i<=n*k; i++) jc[i] = 1ll*jc[i-1]*i%MOD, invjc[i] = 1ll*invjc[i-1]*ksm(i)%MOD;
    for(int i=0; i<k; i++) FFT::g[i] = invjc[i]; fft(FFT::g,tp,1);
    for(int i=1; i<=n; i++){
        pw[i][0] = 1; pw[i][1] = inv[i] = ksm(i);
        for(int j=2; j<=n*k; j++) pw[i][j] = 1ll*pw[i][j-1]*pw[i][1]%MOD;
    }
    for(int i=1; i<n; i++) mul(i);
    for(int i=0; i<n; i++) for(int j=0; j<=i*(k-1); j++) f[i][j] = 1ll*f[i][j]*jc[j]%MOD;
    int ans=0;
    for(int i=1; i<=n; i++){
        int dlt=0;
        for(int j=k-1; j<=i*(k-1); j++)
            upd(dlt,1ll*i*C(j,k-1)%MOD*f[i-1][j-k+1]%MOD*(j+1)%MOD*pw[i][j+1]%MOD*n%MOD*inv[i]);
        if(i&1) upd(ans,1ll*dlt*C(n,i));
        else ddec(ans,1ll*dlt*C(n,i)%MOD);
    }
    cout<<ans<<'\n';
    return 0;
}

/*
3 5
537614966
*/