• [luogu4707]重返现世——min-max容斥拓展+动态规划


    题目大意:

    给定(n)个物品和每个物品出现的概率,收集到至少(k)个物品的期望时间。
    (k leq 10)

    思路:

    好题!

    容斥计算第k大的期望,考虑计算第i大的数的贡献:

    [egin{aligned} &sum_{j=0}^{i-1}{i-1choose j}f_{j}=[i=k]\ &sum_{j=0}^{i}{ichoose j}f_{j}=[i=k-1]\ &f_i=sum_{j=0}^{i}(-1)^{i-j}{ichoose j}[j=k-1]\ &f_i=(-1)^{i-k+1}{ichoose k-1}\ end{aligned} ]

    可得kth-max 的公式为:

    [kth(S)=sum_{Tsubseteq S}(-1)^{|T|-k}{|T|-1choose k-1}min(T) ]

    其中(min(T)=frac{m}{sum_{iin T}p_i})

    我们需要求出所有(|T|geq k)(T),无法直接全部求出,观察到(m=sum{p_i} leq 10^{4}),于是考虑DP。

    (f_{i,j})为选了(i)个数,其中(sum{p_i}=j)的方案数,时间复杂度(Theta(n^2m))

    时间复杂度难以通过,考虑进一步优化:

    (dp_{j,k}) 表示(sum{p_i}=j),且当前求的是第(k)大的方案数系数之积的和,考虑依次将(n)个物品加入,对于(dp_{j,k}),有加入第(i)个物品和不加入第(i)个物品两种选择,转移时主要考虑强制加入第(i)种物品的选择。

    对于强制选择第i个点的部分,集合的大小需要加(1),考虑从前(i-1)个物品的状态转移过来,不难发现我们需要的式子是:

    [sum_{i}(-1)^{i+1-k}{i choose k-1}f_{i,j-p} ]

    其中 i 枚举的是之前选择的集合大小。

    但是上一个状态(dp_{j-p,k-1})可以给我们提供的式子是:

    [sum_{i}(-1)^{i-k+1}{i-1 choose k-2}f_{i,j-p} ]

    不难发现之中我们所缺失的部分为:

    [egin{aligned} &sum_{i}(-1)^{i-k+1}{i-1choose k-1}f_{i,j-p}\ =&-sum_{i}(-1)^{i-k}{i-1choose k-1}f_{i,j-p}\ =&-dp_{j-p,k} end{aligned} ]

    于是到了最后我们得到了转移方程:

    [dp_{j,k}=dp'_{j,k}+dp'_{j-p,k-1}-dp'_{j-p,k}\ ]

    /*=======================================
     * Author : ylsoi
     * Time : 2019.1.16
     * Problem : luogu4707
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
        freopen("luogu4707.in","r",stdin);
        freopen("luogu4707.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
        _=0; T f=1; char c=getchar();
        for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
        for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
        _*=f;
    }
    
    const int maxn=1000+10;
    const int maxm=10000+10;
    const int mod=998244353;
    int n,k,m,p[maxn];
    ll fac[maxn],ifac[maxn];
    ll dp[maxm][maxn],ans;
    
    ll qpow(ll x,ll y){
        ll ret=1; x%=mod;
        while(y){
            if(y&1)ret=ret*x%mod;
            x=x*x%mod;
            y>>=1;
        }
        return ret;
    }
    
    void math_init(){
        fac[0]=1;
        REP(i,1,1e3)fac[i]=fac[i-1]*i%mod;
        ifac[1000]=qpow(fac[1000],mod-2);
        DREP(i,1e3-1,0)ifac[i]=ifac[i+1]*(i+1)%mod;
    }
    
    ll C(int x,int y){
        if(x<0 || y<0 || x<y)return 0;
        return fac[x]*ifac[y]%mod*ifac[x-y]%mod;
    }
    
    void init(){
        read(n),read(k),read(m);
        REP(i,1,n)read(p[i]);
    }
    
    void ad(ll &_,ll __){_=(_+__)%mod;}
    
    void work(){
        k=n-k+1;
        dp[0][0]=1;
        REP(i,1,n){
            DREP(j,m,p[i]){
                DREP(l,k,1){
                    ad(dp[j][l],dp[j-p[i]][l-1]-dp[j-p[i]][l]);
                }
            }
        }
        REP(i,1,m)ad(ans,m*qpow(i,mod-2)%mod*dp[i][k]%mod);
        printf("%lld
    ",(ans+mod)%mod);
    }
    
    int main(){
        //File();
        math_init();
        init();
        work();
        return 0;
    }
    
    
  • 相关阅读:
    Linux Shell编程 sort、wc命令
    Linux Shell编程 sed命令
    Linux Shell编程 awk命令
    Linux Shell编程 cut、print命令
    Linux Shell基础 环境变量配置文件
    Linux Shell基础 read命令
    Linux Shell基础 位置参数变量、预定义变量
    MS DOS 命令大全
    sublime 快捷键
    滚动到页面底部继续加载页面其他内容
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10287658.html
Copyright © 2020-2023  润新知