# Probability dp

In the competition, there will be many questions related to the question of seeking expectation or probability. Although the result may be calculated by mathematical method, the probability or expectation obtained by dp is what the author hopes.

## POJ2096 Collecting Bugs

An unlucky person can collect bugs every day. A software has a \ (s \) subsystem, which will produce \ (n \) different bugs. The probability of each bug belonging to a subsystem is \ (1/s \) and the probability of belonging to a classification is \ (1/n \). Calculate the expectation of the number of days to find \ (n \) bugs and each subsystem finds bugs.

If we calculate by normal mathematical methods, we will find that this is an infinite series, and the calculation will be relatively cumbersome.

However, it is not difficult to find that when \ (n \) bugs have been found and each subsystem finds bugs, the expected period is \ (0 \), which can be used to deduce the expectation of the previous state.

We use \ (f[i][j] \) to represent the expectation of the remaining days when \ (I \) bugs have been found and the \ (j \) subsystem has found bugs. Then it is not difficult to find \ (f[n][s]=0 \).

There are four situations:

1. A new type of bug is found and it is a new subsystem. At this time \ (f[i][j]+=(1-i/s)\times(1-j/n)\times(f[i+1][j+1]+1) \)

2. A new type of bug is found, but it is a duplicate subsystem. At this time \ (f[i][j]+=(1-i/s)\times j/n\times(f[i+1][j]+1) \)

3. Duplicate bug types are found, but they are new subsystems. At this time \ (f[i][j]+=i/s\times(1-j/n)\times(f[i][j+1]+1) \)

4. Duplicate bug types are found and are duplicate subsystems. At this time \ (f[i][j]+=i/s\times j/n\times(f[i][j]+1) \)

Finally, \ (f[i][j] \) is equal to the sum of the above formulas. By combining \ (f[i][j] \), recursion can be carried out.

#include<iostream>
#include<algorithm>
#include<string.h>
#include<iomanip>
#define ll long long
#define pb push_back
#define fast ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1010;
double f[maxn][maxn];
int main()
{
fast;
int n,s;
cin>>n>>s;
memset(f,0,sizeof(f));
f[n][s]=0;
for(int i=n;i>=0;i--)
{
for(int j=s;j>=0;j--)
{
if(i==n && j==s) continue;
f[i][j]=1.0*i/n*(s-j)/s*f[i][j+1]+1.0*(n-i)/n*j/s*f[i+1][j]+1.0*(n-i)/n*(s-j)/s*f[i+1][j+1]+1.0;
f[i][j]=f[i][j]*(1.0*n*s/(n*s-i*j));
}
}
// for(int i=0;i<=n;i++)
// {
//     for(int j=0;j<=s;j++)
//     {
//         cout<<f[i][j]<<' ';
//     }
//     cout<<'\n';
// }
cout<<fixed<<setprecision(4)<<f<<'\n';
}


## NC210477 Take a rich man

Xiao Ming is playing a game with rich men. Specifically, this game has \ (n \) reward points, and each reward point has a certain reward point. At first he stood in position \ (1 \). Every time he throws a sieve with 666 sides. If he throws it to \ (x \), and Xiaoming is standing at the position of \ (i \), Xiaoming will move forward \ (x \) to reach the position of \ (i+x \). If the next step will exceed \ (n \), it must be thrown again. When you reach \ (n \), it is regarded as the end. Ask what is the expected score.

According to the idea of the previous question, we can use \ (f[i] \) to express the expectation of getting a score after the position \ (I \).

1. When \ (i \leq n-6 \), \ (f [i] = a [i] + \ sum \ limits {UJ = I + 1} ^ {I + 6} (f [J] / 6) \)
2. When \ (I > n-6 \), \ (f[i]=a[i]+(f[i+1]+...+f[n])/(n-i) \)
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fast ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 110;
int a[maxn];
double f[maxn]={0};
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
f[n]=a[n];
for(int i=n-1;i>=1;i--)
{
f[i]=a[i];
int num=min(i+6,n)-i;
for(int j=i+1;j<=min(i+6,n);j++)
{
f[i]+=f[j]/num;
}
}
cout<<fixed<<setprecision(7)<<f<<'\n';
}


## NC210481 Sieve game

The title description is not repeated. See the link for details.

Firstly, we can count the probability of all possible sums through triple cycle. Here \ (p[k] \) is used to represent the probability of fraction plus \ (K \). In addition, score zeroing is represented by \ (p \).

Use \ (f[i] \) to represent the expected number of times when the current score is \ (I \). It is easy to get \ (f[i] = \ sum \ limits {k = 3} ^ {18}f[i + k] \ times P [k] + F  \ times P  + 1 \).

However, this formula cannot be recursive directly, because each formula contains \ (f \), and \ (f \) is exactly the result I need.

If each result is related to \ (f \), we might as well set \ (f[i]=A[i]\times f+B[i] \). At this time \ (A[n]=0,B[n]=0 \).

Substituting \ (f[i] \) primitive can obtain:

$$A[i]=\sum\limits_{k=3}^{18}A[i+k]\times p[k]+p$$

$$B[i]=\sum\limits_{k=3}^{18}B[i+k]\times p[k]+1$$

From this recursive formula, we can find \ (A[i] \) and \ (B[i] \), and \ (f=B/(1-A) \, so we can find the answer.

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fast ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 510;
int n;
int k1,k2,k3;
double p={0};
double f[maxn]={0};
double A[maxn]={0};
double B[maxn]={0};
int a,b,c;
int main()
{
cin>>n>>k1>>k2>>k3>>a>>b>>c;
for(int i=1;i<=k1;i++)
{
for(int j=1;j<=k2;j++)
{
for(int m=1;m<=k3;m++)
{
if(i==a && j==b && m==c) continue;
p[i+j+m]++;
}
}
}
for(int i=1;i<=18;i++)
{
p[i]=p[i]/(k1*k2*k3);
}
p=1.0/(k1*k2*k3);
for(int i=n;i>=0;i--)
{
for(int j=3;j<=(k1+k2+k3);j++)
{
A[i]+=p[j]*A[i+j];
B[i]+=p[j]*B[i+j];
}
A[i]+=p;
B[i]+=1;
}
f=B/(1-A);
cout<<fixed<<setprecision(7)<<f<<'\n';
}


## NC210487 canteen

We can use \ (f[i][j] \) to express the probability that when there are \ (I \) individuals in the team and King Jiji is in the front \ (j \) position, he will be in the front \ (k \) position before the door is closed. So we can write the state transition equation.

$f[i][j]= \begin{equation} \begin{cases} p_1f[i][j]+p_2f[i][i]+p_4 & j=1 \\ p_1f[i][j]+p_2f[i][j-1]+p_3f[i-1][j-1]+p_4 & 2\leq j\leq k \\ p_1f[i][j]+p_2f[i][j-1]+p_3f[i-1][j-1] & k<j\leq i \end{cases} \end{equation}$

Similar to the previous question, in the case of \ (j=1 \), both \ (f[i] \) and \ (f[i][i] \) are unknown, so the formula needs to be processed.

First, combine \ (f[i][j] \) with similar items to obtain:

$f[i][j]= \begin{equation} \begin{cases} \frac{p_2f[i][i]}{1-p_1}+\frac{p_4}{1-p_1} & j=1 \\ \frac{p_2f[i][i]}{1-p_1}+\frac{p_3f[i-1][j-1]}{1-p_1}+\frac{p_4}{1-p_1} & 2\leq j\leq k \\ \frac{p_2f[i][i]}{1-p_1}+\frac{p_3f[i-1][j-1]}{1-p_1} & k<j\leq i \end{cases} \end{equation}$

Let \ (k_2,k_3,k_4 \) be equal to \ (\ frac{p_2}{1-p_1},\frac{p_3}{1-p_1},\frac{p_4}{1-p_1} \) respectively, and then we can express all constant terms (here \ (f[i-1][j-1] \) as constants:

$c[i]= \begin{equation} \begin{cases} k_4&j=1 \\ k_3f[i-1][j-1]+k_4&2\leq j \leq k \\ k_3f[i-1][j-1]&k<j\leq i \end{cases} \end{equation}$

This formula can list:

$\begin{equation} \begin{cases} f[i]=k_2f[i][i]+c \\ f[i]=k_2f[i]+c \\ ...\\ f[i][i]=k_2f[i][i-1]+c[i] \end{cases} \end{equation}$

Now, we can find \ (f[i][i] \) through repeated substitution, and then find \ (f[i] \), and then we can deduce all cases.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2010;
int n,m,k;
double p1,p2,p3,p4;
double f[maxn][maxn]={0};
double p[maxn];
double c[maxn];
int main()
{
cin>>n>>m>>k;
cin>>p1>>p2>>p3>>p4;
double k2=p2/(1-p1);
double k3=p3/(1-p1);
double k4=p4/(1-p1);
f=p4/(1-p1-p2);
p=1;
for(int i=1;i<=n;i++)
{
p[i]=p[i-1]*k2;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
if(j<=k) c[j]=f[i-1][j-1]*k3+k4;
else c[j]=f[i-1][j-1]*k3;
}
double tmp=0;
for(int j=1;j<=i;j++)
{
tmp+=p[i-j]*c[j];
}
f[i][i]=tmp/(1-p[i]);
f[i]=k2*f[i][i]+k4;
for(int j=2;j<i;j++)
{
f[i][j]=k2*f[i][j-1]+c[j];
}
}
cout<<fixed<<setprecision(5)<<f[n][m]<<'\n';
}


Posted by apenster on Tue, 02 Nov 2021 04:43:47 -0700