AtCoder Beginner Contest 226 H - Random Kth Max

H - Random Kth Max

题意:

给你 N N N连续随机变量 X 1 , X 2 . . . X n X_1,X_2...X_n X1,X2...Xn.

其中 X i X_i Xi 在区间 [ L i , R i ] [L_i,R_i] [Li,Ri]内均匀分布,求第 K K K大数的期望。

题解

一、求解子问题

先看这个子问题:

N N N连续随机变量 X 1 , X 2 . . . X n X_1,X_2...X_n X1,X2...Xn都服从 U ( 0 , 1 ) U(0, 1) U(0,1),求第 k k k大的数的期望。

我们在大学的**《概率论与数理统计》**学过,均匀分布的概率分布函数 F ( x ) = x F(x)=x F(x)=x.对于整个问题,其概率分布函数 F X ( x ) = P ( X < x ) F_X(x)=P(X<x) FX(x)=P(X<x), 也就是第 K K K大的数小于 x x x的概率。

这个期望很难用正常算法解出来,所以官方题解给出了另一种反向思路:

我们算 1 − F ( x ) 1-F(x) 1F(x), 也就是第 K K K大的数大于 x x x的概率。

这个事件可以分为以下情况:(等于 x x x归于任何一种情况都行)

  • K K K个数大于 x x x, N − K N-K NK个数小于 x x x;
  • K + 1 K+1 K+1个数大于 x x x N − K − 1 N-K-1 NK1个数小于 x x x;

。。。。。

  • N N N个数全大于 x x x.

所以,可以写出:
KaTeX parse error: No such environment: equation at position 8: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲ 1-F(x)=\sum_{i…
我们学过,连续随机变量的期望可以用以下公式计算:
E ( X ) = ∫ − ∞ + ∞ x f ( x ) d x (2) E(X)=\int_{-\infty}^{+\infty}xf(x)dx \tag{2} E(X)=+xf(x)dx(2)
其中 f ( x ) f(x) f(x)为概率密度函数。我们可以对上述式子使用分部积分变形:
∫ x f ( x ) d x = ∫ x d F ( x ) = x F ( x ) − ∫ F ( x ) d x (3) \int xf(x)dx = \int xdF(x)=xF(x)-\int F(x)dx \tag{3} xf(x)dx=xdF(x)=xF(x)F(x)dx(3)
X X X的取值范围为 [ a , b ] [a,b] [a,b],带入上式子:
b F ( b ) − a F ( a ) − ∫ a b F ( x ) d x = b − ∫ a b F ( x ) d x = a + ( b − a ) − ∫ a b F ( x ) d x = a + ∫ a b ( 1 − F ( x ) ) d x (4) bF(b)-aF(a)-\int_a^bF(x)dx =b-\int_a^bF(x)dx \\ =a+(b-a)-\int_a^bF(x)dx \\ =a+\int_a^b(1-F(x))dx \tag{4} bF(b)aF(a)abF(x)dx=babF(x)dx=a+(ba)abF(x)dx=a+ab(1F(x))dx(4)

( 1 ) (1) (1)代入 ( 4 ) (4) (4)
E ( X ) = ∫ 0 1 ( ∑ i = k n C n i ( 1 − x ) i x ( n − i ) ) d x = ∑ i = k n C n i ∫ 0 1 ( 1 − x ) i x ( n − i ) d x (5) E(X) = \int_0^1(\sum_{i=k}^nC_{n}^i(1-x)^ix^{(n-i)})dx \\ = \sum_{i=k}^nC_{n}^i\int_0^1(1-x)^ix^{(n-i)}dx \tag{5} E(X)=01(i=knCni(1x)ix(ni))dx=i=knCni01(1x)ix(ni)dx(5)

根据beta函数 的定义,积分里面那东西等于 B ( n − i + 1 , i + 1 ) B(n-i+1,i+1) B(ni+1,i+1), 又根据beta函数和gamma函数的关系,有
B ( P , Q ) = Γ ( P ) Γ ( Q ) Γ ( P + Q ) (6) B(P, Q) = \frac{\Gamma(P)\Gamma(Q)}{\Gamma(P+Q)} \tag6 B(P,Q)=Γ(P+Q)Γ(P)Γ(Q)(6)
带入 ( 5 ) (5) (5):
E ( X ) = ∑ i = k n C n i ∫ 0 1 ( 1 − x ) i x ( n − i ) d x = ∑ i = k n C n i ( n − i ) ! i ! ( n + 1 ) ! = ∑ i = k n 1 1 + n = n − k + 1 1 + n (7) E(X) = \sum_{i=k}^nC_{n}^i\int_0^1(1-x)^ix^{(n-i)}dx \\ = \sum_{i=k}^nC_{n}^i \frac{(n-i)!i!}{(n+1)!} \\ = \sum_{i=k}^n\frac{1}{1+n} \\ = \frac{n-k+1}{1+n} \tag7 E(X)=i=knCni01(1x)ix(ni)dx=i=knCni(n+1)!(ni)!i!=i=kn1+n1=1+nnk+1(7)
这样我们就把子问题算出来了。

二、利用子问题计算原题

我们可以利用子问题的结论,把原题拆成一个一个线段,先让某个排名的数落在长度为1的线段里,再算线段里面某个名次对整个答案的贡献。

因为只是排名,前面几个数怎么选对后面没关系,因此可以用DP来做:

对每个线段 [ A , A + 1 ] [A, A+1] [A,A+1], d p ( i , j , k ) dp(i,j,k) dp(i,j,k)表示前 i i i个数,有 j j j个数在线段右边, k k k个数在线段里面的概率。

那么计算这个dp的时候,我们通过第i个点的选取位置,决定该从哪个状态转移过来,无外乎三种情况:

  • i i i个点取在 A A A左边,那么仍有 j j j个数在线段右边, k k k个数在线段里面,跟 d p [ i − 1 ] [ j ] [ k ] dp[i-1][j][k] dp[i1][j][k]有关;

  • i i i个点取在线段内部,那么有 j j j个数在线段右边, k − 1 k-1 k1个数在线段里面,跟 d p [ i − 1 ] [ j ] [ k − 1 ] dp[i-1][j][k-1] dp[i1][j][k1]有关;

  • i i i个点取在 A + 1 A+1 A+1右边,那么有 j − 1 j-1 j1个数在线段右边, k k k个数在线段里面,跟 d p [ i − 1 ] [ j − 1 ] [ k ] dp[i-1][j-1][k] dp[i1][j1][k]有关;

实现的时候还需要判断下能不能取到,和数组越不越界。

然后算最终答案,第一维肯定是 n n n不用说了,分别讨论每个线段,每个 ( j , s ) (j,s) (j,s)对答案的贡献:

首先,出现在线段 [ a , a + 1 ] [a, a+1] [a,a+1] 中有 s s s个数,右边有 j j j个数的概率是 d p [ n ] [ j ] [ s ] dp[n][j][s] dp[n][j][s], 我们要计算这种概率下,整体第 K K K大的期望,那么就等价于线段里面的第 K − j K-j Kj大的期望,利用第一部分中已有结论,这个期望值就是 1 + k − j s + 1 1+\frac{k-j}{s+1} 1+s+1kj, 线段是从a开始的,还要加上偏移量a,所以答案等于:
∑ a = 0 m a x ( R i ) ∑ ( j , s ) d p [ n ] [ j ] [ s ] ∗ ( a + 1 + k − j s + 1 ) \sum_{a=0}^{max(R_i)}\sum_{(j, s)}dp[n][j][s]*(a+1+\frac{k-j}{s+1}) a=0max(Ri)(j,s)dp[n][j][s](a+1+s+1kj)
最终的时间复杂度约为 O ( n 4 ) O(n^4) O(n4),n只有100,可过。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 110;
const int MOD = 998244353;

int n, K;
ll dp[N][N][N], inv[N];
ll l[N], r[N];


ll qpow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

void init() {
    for (int i = 1; i < 110; i++) {
        inv[i] = qpow(i, MOD - 2);
    }
}
int main() {
    cin >> n >> K;
    ll minl = 200, maxr = -1;
    for (int i = 1; i <= n; i++) {
        cin >> l[i] >> r[i];
        minl = min(minl, l[i]);
        maxr = max(maxr, r[i]);
    }

    init();
    ll res = 0;
    for (ll A = minl; A <= maxr; A++) {
        memset(dp, 0, sizeof(dp));
        dp[0][0][0] = 1; // 没有数,那么只有0 0 一种情况

        for (int i = 1; i <= n; i++) {

            for (int j = 0; j < K; j++) {
                for (int k = 0; k <= i; k++) {
                    // cout << k << ',' << i << endl;
                    ll& x = dp[i][j][k];
                    // case 1: 左边
                    if (A >= l[i]) { // 能选得到才有意义
                        ll temp = dp[i - 1][j][k] * (min(r[i], A) - l[i]) % MOD;
                        temp = temp * inv[r[i] - l[i]] % MOD;
                        x = (x + temp) % MOD;
                    }

                    // case2
                    if (l[i] <= A && A + 1 <= r[i] && k >= 1) {
                        ll temp = dp[i - 1][j][k - 1] * inv[r[i] - l[i]] % MOD;
                        x = (x + temp) % MOD;
                    }

                    // case 3:
                    if (A + 1 <= r[i] && j >= 1) {
                        ll temp = dp[i - 1][j - 1][k] * (r[i] - max(l[i], A + 1)) % MOD;
                        temp = temp * inv[r[i] - l[i]] % MOD;
                        x = (x + temp) % MOD;
                    }
                }
            }

            for (int j = 0; j < K; j++)
                for (int s = 0; s <= n; s++)
                    if (K - j <= s) {
                        ll aa = dp[n][j][s];
                        ll temp1 = (K-j)*inv[s+1] % MOD;
                        ll temp2 = (A+1+MOD-temp1) % MOD;
                        res += aa * temp2 % MOD;
                        res %= MOD;
                    }

        }
    }

    cout << res << endl;
    return 0;
}
### 回答1: atcoder beginner contest 226 是一个由 AtCoder 组织的初学者比赛,旨在为初学者提供一个锻炼自己编程能力的机会。比赛通常包括多个问题,难度从简单到困难不等,参赛者需要在规定时间内解决尽可能多的问题。该比赛吸引了来自世界各地的初学者参加,是一个非常有趣和有挑战性的比赛。 ### 回答2: AtCoder Beginner Contest 226 是日本AtCoder举办的一场新手比赛。这场比赛通常设有三到五个问题,题目难度逐渐增加,旨在让初学者锻炼编程技巧和算法思维。 比赛开始时,参赛选手需要在指定时间内独立解决各个问题。比赛网站提供了在线编程环境,选手可以使用C++、Python、Java等常见编程语言提交代码。解题的时间和代码正确性都会影响选手的得分。 题目的类型非常多样,通常涵盖了数据结构、图论、动态规划、贪心等算法知识点。选手可以从题目描述中获得输入输出的要求,并根据题意编写代码来解决问题。 在比赛过程中,选手需要尽快理解题目,并设计出正确的解决方案。正确的思路及合理的实现将是获得高分的关键。因此,参赛选手需要在比赛前充分复习算法知识、熟练掌握编程语言,并在实践中提高自己的编码能力。 ATCoder Beginner Contest 226 不仅考验了参赛选手的算法和编程水平,还对他们的应变能力和时间管理能力提出了要求。即使是经验丰富的选手,也需要在限定时间内思考问题、调试代码,尽量取得更好的成绩。 通过参加此类竞赛,选手可以提高自己的编程技能、拓宽解题思路,并加深对算法和数据结构的理解。同时,比赛过程中还可以与其他选手交流经验,提高团队合作和竞争意识。 总而言之,AtCoder Beginner Contest 226 是一场适合初学者的编程比赛,通过参与其中,选手可以提高自己的编程能力,拓宽算法思维,并享受竞赛的乐趣。 ### 回答3: AtCoder Beginner Contest 226是AtCoder举办的一场面向初学者的比赛。这场比赛通常由3到4道问题组成,涵盖了算法和编程的各个方面。 比赛开始时,参赛选手将在规定的时间内独立解答问题。每个问题都有不同的难度和分值,选手需要在限定时间内尽可能解决更多的问题,并在解答正确的情况下获得更高的得分。 比赛过程中,选手可以使用自己熟悉的编程语言,如C ++,Java或Python。他们需要运用算法和数据结构的知识,设计出高效的解决方案,并考虑到时间和空间的复杂度来优化代码。 此外,比赛还严格限制了提交次数和解答时间,这要求选手在思考和编码时要快速和准确。选手需要经常检查他们的代码是否符合问题的要求,并在必要时进行调试。 比赛结束后,AtCoder将根据选手的成绩排名,并授予他们相应的奖励。排在前几名的选手将获得奖牌,他们的成绩也将被列入AtCoder的排名榜。 总的来说,AtCoder Beginner Contest 226为初学者提供了一个锻炼算法和编程能力的机会。通过参加这样的比赛,选手可以提高他们的技能,并与其他热爱编程的人分享和交流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值