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
*/
posted @ 2021-06-29 16:44  oisdoaiu  阅读(33)  评论(0编辑  收藏  举报