牛客2021多校第四场B(生成函数, 期望) 题解

成功用这道题生成函数入门了

题目描述

牛客2021多校第四场B题

生成 i ∈ [ 1 , n ] i \in [1,n] i[1,n]​的数字的概率分别为 p i p_i pi​​​

按照以下方式生成数字序列 a i a_i ai

  1. 生成数字 x x x
  2. 判断数字 x x x​是否为 a i a_i ai​​中的最大值, 如果是则重复1, 否则停止

通过以上方式生成一共 l e n len len​个数, 则得分为 l e n 2 len^2 len2

求得分的期望

其中 p i p_i pi w i ∑ 1 n w i \frac{w_i}{\sum_1^nw_i} 1nwiwi​的形式给出

输出概率对 998244353 998244353 998244353取模
0 ≤ w i ≤ 1 0 6 2 ≤ n ≤ 100 \\0\leq w_i \leq 10^6 \\2\leq n \leq 100 0wi1062n100

题目分析

一个没有结束的数字序列一定是单调不降的, 比如 1 , 1 , 1 , 2 , 2 , 3 1,1,1,2,2,3 1,1,1,2,2,3

如果一个序列的长度 l e n len len​​​​​​​​​​超过 i i i​​​​​​​​​​​时对应的生成概率为 p ( l e n > i ) p(len>i) p(len>i)​​​​​​​​​​​​​​​​​,那么就可以知道这个序列下一个数停止的概率为 p ( l e n > i ) − p ( l e n > i + 1 ) p(len>i) - p(len>i+1) p(len>i)p(len>i+1)​​​​​​​​​​,那么再乘上 ( i + 1 ) 2 (i+1)^2 (i+1)2​​​​​​​就得到了 i + 1 i+1 i+1​​​​​​​​​​长度的得分期望

那么求 ∑ 0 ∞ [ p ( l e n > i ) − p ( l e n > i + 1 ) ] ( i + 1 ) 2 \sum_0^\infty [p(len>i) - p(len >i+1)](i+1)^2 0[p(len>i)p(len>i+1)](i+1)2​​​​就得到了总的期望

对这个式子进行一下化简
∑ 0 ∞ [ p ( l e n > i ) − p ( l e n > i + 1 ) ] ( i + 1 ) 2 = ∑ 0 ∞ [ p ( l e n > i ) ( i + 1 ) 2 − p ( l e n > i + 1 ) ( i + 1 ) 2 ] = p ( l e n > 0 ) ( 0 + 1 ) 2 + ∑ 1 ∞ p ( l e n > i ) [ ( i + 1 ) 2 − i 2 ] − p ( l e n > ∞ ) ( ∞ + 1 ) 2 = p ( l e n > 0 ) ( 0 + 1 ) 2 + ∑ 1 ∞ p ( l e n > i ) [ ( i + 1 ) 2 − i 2 ] = ∑ 0 ∞ p ( l e n > i ) [ ( i + 1 ) 2 − i 2 ] = ∑ 0 ∞ p ( l e n > i ) ( 2 i + 1 ) \sum_0^\infty[p(len > i) - p(len > i + 1)](i + 1)^2\\ = \sum_0^\infty [p(len>i)(i+1)^2 - p(len > i+1)(i+1)^2]\\ =p(len > 0)(0+1)^2 + \sum_1^\infty p(len>i)[(i+1)^2 - i^2] - p(len >\infty)(\infty + 1)^2\\ =p(len>0)(0+1)^2 + \sum_1^\infty p(len>i)[(i+1)^2 - i^2]\\ =\sum_0^\infty p(len>i)[(i+1)^2 - i^2]\\ =\sum_0^\infty p(len>i)(2i+1) 0[p(len>i)p(len>i+1)](i+1)2=0[p(len>i)(i+1)2p(len>i+1)(i+1)2]=p(len>0)(0+1)2+1p(len>i)[(i+1)2i2]p(len>)(+1)2=p(len>0)(0+1)2+1p(len>i)[(i+1)2i2]=0p(len>i)[(i+1)2i2]=0p(len>i)(2i+1)

那么如何求 p ( l e n > i ) p(len>i) p(len>i)呢​​

构造一个生成函数 g i ( x ) = ∑ k = 0 ∞ p i x k = 1 1 − p I x g_i(x) =\sum_{k=0}^{\infty}p_ix^k = \frac{1}{1-p_Ix} gi(x)=k=0pixk=1pIx1的系数来表示对于第 i i i个数生成了 k k k次的生成概率,那么可以知道, 生成所有序列的生成函数,就是 f ( x ) = ∏ i = 1 n g i ( x ) f(x) = \prod_{i=1}^{n}g_i(x) f(x)=i=1ngi(x) 其中 f ( x ) f(x) f(x) x i x^{i} xi的系数表示未结束的序列长度为 i i i的概率, 因为生成的序列长度已经为 i i i了,所以这个序列长度最终至少为 i + 1 i+1 i+1,因此这个系数就是 p ( l e n > i ) p(len>i) p(len>i)​​​

因此 f ( x ) = ∑ 0 ∞ p ( l e n > i ) x i = ∏ i = 1 n 1 1 − p i x f(x)=\sum_0^\infty p(len>i)x^i = \prod_{i=1}^n\frac{1}{1-p_ix} f(x)=0p(len>i)xi=i=1n1pix1​​​

f ′ ( x ) = ∑ 0 ∞ i ∗ p ( l e n > i ) x i − 1 = f ( x ) ∗ ( ∑ 0 n p i 1 − p i x ) f'(x) = \sum_0^\infty i*p(len>i)x^{i-1} = f(x)*(\sum_0^n\frac{p_i}{1-p_ix} ) f(x)=0ip(len>i)xi1=f(x)(0n1pixpi)​​​(复合函数的求导)

f ( x ) , f ′ ( x ) f(x),f'(x) f(x)f(x)​代入原式
∑ 0 ∞ p ( l e n > i ) ( 2 i + 1 ) = 2 ∗ ∑ 0 ∞ i ∗ p ( l e n > i ) + ∑ 0 ∞ p ( l e n > i ) = 2 ∗ f ′ ( 1 ) + f ( 1 ) \sum_0^\infty p(len>i)(2i+1) \\=2*\sum_0^\infty i*p(len>i) + \sum_0^\infty p(len>i) \\=2*f'(1)+f(1) 0p(len>i)(2i+1)=20ip(len>i)+0p(len>i)=2f(1)+f(1)
这样就可以计算啦

复杂度是 O ( n ) O(n) O(n)

所以也许可以把n再扩大一些

题目踩坑

不管算多少步,每一步都要取模, 不要因为嫌麻烦在某一步不取模!

不知道什么时候就爆long long了

记得模意义下的除法是逆元,可以使用费马小定理

AC代码

代码丑陋,仅供参考

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 100;
const int MOD = 998244353;
typedef long long ll;
ll qp(ll a, int b)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1)
        {
            ans = (ans * a) % MOD;
        }
        b >>= 1;
        a = (a * a) % MOD;
    }
    return ans;
}
ll inv(ll a)
{
    return qp(a, MOD - 2);
}
int wi[MAXN + 100];
int main()
{
    int n;
    ll sum = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &wi[i]);
        sum += wi[i];
    }
    sum %= MOD;
    ll f1 = 1;
    ll df1 = 0;
    for(int i = 1; i <= n; ++i)
    {
        ll swi = ((sum - wi[i])%MOD + MOD) % MOD;
        f1 *= (sum * inv(swi)) % MOD;
        f1 %= MOD;
        df1 += (wi[i] *  inv(swi)) % MOD;
        df1 %= MOD;
    }
    df1 *= f1;
    df1 %= MOD;
    ll totans = ((df1 + df1) % MOD + f1) % MOD;
    printf("%lld", totans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值