c++概率dp——超实用的数据结构

1. 概念引入

在做题目之前,我们需要知道概率是什么。

概率,亦称“或然率”,它是反映随机事件出现的可能性大小。

在讨论一个事件的概率的时候,我们需要搞清楚概率的讨论范围,比如,掷硬币的概率就不考虑天气等其他因素。
为了简化叙述,我们采用术语:

  • P ( A ) P(A) P(A)表示随机事件A发生的概率
  • 样本点:一个不可再细分的随机现象,叫做样本点。
  • 样本空间 Ω \Omega Ω:所有样本点构成的集合。
  • 随机事件:样本空间 Ω \Omega Ω的子集。

我们用掷骰子来举例:
P ( ⋃ i = 1 n A i ) = ( − 1 ) 0 ∑ i = 1 n P ( A i ) + ( − 1 ) 1 ∑ 0 < i < j ≤ n P ( A i A j ) + . . . + ( − 1 ) n − 1 P ( A 1 A 2 . . . A n ) P(\bigcup_{i=1}^{n}A_{i})=(-1)^{0}\sum_{i=1}^{n}P(A_{i})+(-1)^{1}\sum_{0<i<j\leq n} ^{}P(A_{i}A_{j})+...+(-1)^{n-1}P(A_{1}A_{2}...A_{n}) P(i=1nAi)=(1)0i=1nP(Ai)+(1)10<i<jnP(AiAj)+...+(1)n1P(A1A2...An)指的是朝上的面为:{ 1 1 1}。
样本空间指的是朝上的面为:{ 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 1,2,3,4,5,6}。
随机事件指的是朝上的面为:{ 1 , 2 1,2 1,2}。
这里要注意:一个样本点一定是一个随机事件,但一个随机事件不一定是一个样本点

其实,概率可以理解为一个集合,它可以满足:
非负性,规范性,可数可加性,以及容斥原理
容斥原理的公式是:
P ( ⋃ i = 1 n A i ) = ( − 1 ) 0 ∑ i = 1 n P ( A i ) + ( − 1 ) 1 ∑ 0 < i < j ≤ n P ( A i A j ) + . . . + ( − 1 ) n − 1 P ( A 1 A 2 . . . A n ) P(\bigcup_{i=1}^{n}A_{i})=(-1)^{0}\sum_{i=1}^{n}P(A_{i})+(-1)^{1}\sum_{0<i<j\leq n} ^{}P(A_{i}A_{j})+...+(-1)^{n-1}P(A_{1}A_{2}...A_{n}) P(i=1nAi)=(1)0i=1nP(Ai)+(1)10<i<jnP(AiAj)+...+(1)n1P(A1A2...An)

我们还要学会计算期望值:
期望值指的的是随机变量的值乘以其概率的总和

2. 例题精讲

话不多说,我们直接看例题。

2.1 危险迷宫

题目链接

2.1.1 代码

下面附上代码

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define For(i, a, b) for (int i = a; i <= b; i++)
typedef pair<int, int> PII;
const int N = 1e6;
int n, a[N], flag, ans, ans1;
int gcd(int a, int b)
{
    if (b == 0)
        return a;
    else
        return gcd(b, a % b);
}
int ee()
{
    for (int i = 1; i <= n; i++)
    {
        ans += abs(a[i]);
    }
    for (int i = 1; i <= n; i++)
    {
        if (a[i] > 0)
            ans1 += 1;
    }
    return ans;
}
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        flag = true, ans = 0, ans1 = 0;
        memset(a, 0, sizeof a);
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            if (a[i] >= 0)
            {
                flag = false;
            }
        }
        if (flag)
        {
            cout << "inf\n";
            continue;
        }
        ee();
        int flag1 = gcd(ans, ans1);
        cout << ans / flag1 << "/" << ans1 / flag1 << endl;
    }
    return 0;
}

2.1.2 AC图片

在这里插入图片描述

2.2 收集黄金

题目链接

2.2.1 代码

这道题大家可以自己思考,我也会适当添加注释的。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define For(i, a, b) for (int i = a; i <= b; i++)
typedef pair<int, int> PII;
const int N = 1e4;
const int P = 1e9 + 7;
int n, a[N], dp[N];
/*
状态设计:dp[i]表示从第 i 位置开始,按照游戏规则,最终可以得到的期望黄金数量
答案: dp[1]
初值:dp[n] = a[n];
转移:dp[i] - (dp[i + 1] + dp[i + 2] + ...... + dp[min(n, 1 + 6)]) / {min(n, j + 6) - j}, j = 1, ......, n - 1
)
*/
int inv(int x) {
	int res = 1;
	int n = P - 2;
	while (n) {
		if (n & 1)
			res = res * x % P;
		x = x * x % P;
		n >>= 1;
	}
	return res;
}
void solve()
{
    memset(dp, 0, sizeof dp);
    cin >> n;
    For(i, 1, n)
    {
        cin >> a[i];
    }
    dp[n] = a[n];
    for (int i = n - 1; i >= 1;i--){
        For(j, i + 1, min(n, i + 6)){
            dp[i] = (dp[i] + dp[j]) % P;
        }
        dp[i] = dp[i] * inv(min(n, i + 6) - i) % P;
        dp[i] = (dp[i] + a[i]) % P;
        
    }
    cout << dp[1] % P << endl;
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

2.2.2 AC图片

3.结语

今天的文章就到这里啦,三连必回qwq!

  • 26
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值