zoukankan      html  css  js  c++  java
  • 重返现世——Min-Max容斥+DP

    题面

      洛谷P4707

    解析

      先来证一下拓展$Min-Max$容斥:

      去证:$$kthmax(S) = sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}min(T)$$

      证明:

      构造容斥系数,设:$$kthmax(S) = sum_{T subseteq S}f(|T|)min(T)$$

      考虑$min(T)$为同一元素的系数之和,即$sum f(|T|)$。对于第$x+1$大的元素这个系数之和为$sum_{i=0}^xinom{x}{i}f(i+1)$,就是在比它大的$x$个数里选$i$个与它组成$T$集合。

      则有:$$[x==k-1]=sum_{i=0}^xinom{x}{i}f(i+1)$$

      二项式反演:$$f(x+1)=sum_{i=0}^x(-1)^{x-i}inom{x}{i}[i==k-1]$$$$f(x+1)=(-1)^{x-k+1}inom{x}{k-1}$$

      所以$$f(x)=(-1)^{x-k}inom{x-1}{k-1}$$

      故:$$egin{align*}kthmax(S) &= sum_{T subseteq S}f(|T|)min(T)\ &=sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}min(T)end{align*}$$

      得证


        题目要求第$K$小,其实就是$n+1-K$大

      因为$E(kthmax(S)) = sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}E(min(T))$

      $E(min(T))$表示第一次选中$T$内的数的期望时间,等于$frac{1}{sum_{i in T}frac{p_i}{m}}=frac{m}{sum_{iin T}p_i}$

      所以:$$egin{align*}E(kthmax(S)) &= sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}frac{m}{sum_{iin T}p_i}\ &= msum_{T subseteq S}frac{(-1)^{|T|-k}inom{|T|-1}{k-1}}{sum_{iin T}p_i}end{align*}$$

      但这道题$n leqslant 1000$,无法枚举子集,只能$DP$

      设集合$S_i=egin{Bmatrix}1,2,cdots,iend{Bmatrix}$,$f_{i,j,k}$表示考虑前$i$大的数,满足$sum p_x = j,xin T$的所有集合$T,Tsubseteq S_i$的$sum (-1)^{|T|-k}inom{|T|-1}{k-1}$值

      当$T$集合内不含$i$时,则:$f_{i,j,k}=f_{i-1,j,k}$

      当$T$集合内含$i$时,$$egin{align*}f_{i,j,k}&=sum_{iin T, T subseteq S_i} (-1)^{|T|-k}inom{|T|-1}{k-1}\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom {|T|}{k-1}\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}(inom{|T|-1}{k-2}+inom{|T|-1}{k-1})\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom{|T|-1}{k-2}+sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom{|T|-1}{k-1}\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom{|T|-1}{k-2}-sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k}inom{|T|-1}{k-1}\ &= f_{i-1,j-p_i,k-1}-f_{i-1,j-p_i,k}end{align*}$$

      故:$f_{i,j,k}=f_{i-1,j,k}+f_{i-1,j-p_i,k-1}-f_{i-1,j-p_i,k}$

      边界:$f_{i,0,0}=1$

      时间复杂度:$O(nm|n-K|)$

     代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int maxn = 1005, mod = 998244353;
    
    ll qpow(ll x, ll y)
    {
        ll ret = 1;
        while(y)
        {
            if(y&1)
                ret = ret * x % mod;
            x = x * x % mod;
            y >>= 1;
        }
        return ret;
    }
    
    ll add(ll x, ll y)
    {
        return x + y < mod? x + y: x + y - mod;
    }
    
    ll rdc(ll x, ll y)
    {
        return x - y < 0? x - y + mod: x - y;
    }
    
    int n, m, K;
    int a[maxn];
    ll dp[2][maxn*10][12];
    
    int main()
    {
        scanf("%d%d%d", &n, &K, &m);
        K = n + 1 - K;
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        int pre, now;
        dp[0][0][0] = 1;
        for(int i = 1; i <= n; ++i)
        {
            now = (i & 1);
            pre = (now ^ 1);
            memset(dp[now], 0, sizeof(dp[now]));
            dp[now][0][0] = 1;
            for(int j = 0; j < a[i]; ++j)
                for(int k = 1; k <= K; ++k)
                    dp[now][j][k] = dp[pre][j][k];
            for(int j = a[i]; j <= m; ++j)
                for(int k = 1; k <= K; ++k)
                    dp[now][j][k] = add(dp[pre][j][k], rdc(dp[pre][j-a[i]][k-1], dp[pre][j-a[i]][k]));
        }
        ll ans = 0;
        for(int i = 1; i <= m; ++i)
            ans = add(ans, (dp[now][i][K] * qpow(i, mod - 2) % mod) * m % mod);
        printf("%lld", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    [linux] 将socket设置为非阻塞(nonblocking)
    翻译—IvorHorton的Begining Visual C++ 2005 [第一章]
    深入解析ATL(第二版ATL8.0)(1.11.3节)
    gdb使用初步
    编程其实就是一个不断做出选择的过程
    windows和linux下多线程的一些区别
    makefile编写入门
    深入解析ATL(第二版ATL8.0)(1.41.7节)
    深入解析ATL(第二版ATL8.0)(1.81.10节)
    用gdb调试子进程
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/12398847.html
Copyright © 2011-2022 走看看