目录
食堂
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
吉吉国王偶尔会回想起自己的高中时代。在吉吉国王的高中时代,下课后冲向食堂是每个学生的基本操作,但是总得有人失败,为什么不能是我,实际上吉吉国王在打饭这件事上也是失败过很多次,比如没带饭卡,走错窗口,甚至食堂关门。
吉吉国王的高中食堂排队可以看成一个长度为nnn的队列,一开始吉吉国王站在mmm这个位置上,一般来说,窗口前的第一个人在打饭的时候会发生四种情况。
第一种情况是打饭的时候窗口没人,这个时候要等待一会儿,发生的概率是p1p_1p1。
第二种情况是发现自己没带饭卡,这个时候就要回去拿饭卡并且排到了队列的末尾,发生的概率是p2p_2p2。(这里认为每个人只有在即将打饭的时候才会去摸饭卡,只有这时才有发现自己没带饭卡的机会。)
第三种情况是打饭成功,这个时候队列的长度减一,发生的概率是p3p_3p3。
第四种情况是食堂关门,这个时候大家都不能打饭了,发生的概率是p4p_4p4。
吉吉国王老倒霉蛋了,经常在食堂关门的时候排在队伍的前面,因此他想知道这样的事件发生的概率。现在你需要告诉吉吉国王在食堂关门时他排在队伍的前kkk位的概率。
输入描述:
一行七个数表示n,m,k,p1,p2,p3,p4.
输出描述:
输出一个小数表示答案,小数点后保留五位。
示例1
输入
4 4 1 0.372818 0.318286 0.220035 0.0888615
输出
0.15428
备注:
1 <= k<=m<=n<=2000
0<=p1,p2,p3,p4<=1,p1+p2+p3+p4=1.
思路解析:
if j==1
f[i][j] = p1*f[i][j] + p2*f[i][i] + p4
p1 * dp[i][j]表示当前食堂每人停留在此状态,最后成功的概率,p2*f[i][i]表示自己没带饭卡回到队尾最后成功的概率,p4表示当前食堂关门,成功。
if j>=2&&j<=k
f[i][j]=p1*f[i][j]+p2*f[i][j-1]+p3*f[i-1][j-1]+p4
p1 * dp[i][j]表示当前食堂每人停留在此状态,最后成功的概率,p2*f[i][j-1]表示当前队伍第一个人没带饭卡回到队尾最后成功的概率,p3*f[i-1][j-1]表示当前队伍第一个人打饭成功,最后成功的概率,p4表示当前食堂关门,成功。
if j>k
f[i][j]=p1*f[i][j]+p2*f[i][j-1]+p3*f[i-1][j-1]
p1 * dp[i][j]表示当前食堂每人停留在此状态,最后成功的概率,p2*f[i][j-1]表示当前队伍第一个人没带饭卡回到队尾最后成功的概率,p3*f[i-1][j-1]表示当前队伍第一个人打饭成功,最后成功的概率。
由于两边都有f[i][j],那么经过移项合并同类项可以得到:
j==1
f[i][1]=p2/(1-p1)*f[i][i]+p4/(1-p1)
j<=k
f[i][j]=p2/(1-p1)*f[i][j-1]+p3/(1-p1)*f[i-1][j-1]+p4/(1-p1)
j<=n
f[i][j]=p2/(1-p1)*f[i][j-1]+p3/(1-p1)*f[i-1][j-1]
因此我们令:
a=p2/(1-p1)
b=p3/(1-p1)
c=p4/(1-p1)
观察式子发现当计算到f[i][j]的时候,f[i-1][j-1]已经被算出来了,因此我们可以将其看作常数项,继续定义化简:
j==1
d[j]=c
j<=k
d[j]=b*f[i-1][j-1]+c
j<=n
d[j]=b*f[i-1][j-1]
最后式子就被化简为了:
j==1
f[i][1] = a*f[i][i]+d[1]
j>=2
f[i][j]=a*f[i][i-1]+d[j]
多列几项f[i][j]可以发现从第一个式子开始全部带进最后一个式子可以算出f[i][i],
比如:i == 3时,
dp[i][1] = a * dp[i][i] + d[1]
dp[i][2] = a * dp[i][1] + d[2]
dp[i][3] = a * dp[i][2] + d[3] = dp[i][i]
最后将前两项带入最后一项可以进行化简,最后发现规律,这样就可以快速求出dp[i][i]
因此先算出f[i][i]:
f[i][i]=(∑p[i-k]d[k])/(1-p[i])
然后再递推求出其他f[i][j]即可~
代码实现:
import java.util.Scanner;
/**
* @ProjectName: study3
* @FileName: Ex4
* @author:HWJ
* @Data: 2023/11/27 21:15
*/
public class Ex4 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
int k = input.nextInt();
double p1 = input.nextDouble();
double p2 = input.nextDouble();
double p3 = input.nextDouble();
double p4 = input.nextDouble();
double[][] dp = new double[n + 1][n + 1];
double[] p = new double[n + 1];
double a = p2 / (1 - p1);
double b = p3 / (1 - p1);
double c = p4 / (1 - p1);
p[0] = 1;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * a;
}
dp[1][1] = p4 / (1 - p1 - p2);
double[] d = new double[n + 1];
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if (j == 1) {
d[j] = c;
} else if (j >= 2 && j <= k) {
d[j] = b * dp[i - 1][j - 1] + c;
} else if (j > k) {
d[j] = b * dp[i - 1][j - 1];
}
}
for (int j = 1; j <= i; j++) {
dp[i][i] += d[j] * p[i - j];
}
dp[i][i] /= (1.0 - p[i]);
for (int j = 1; j <= i; j++) {
if (j == 1){
dp[i][j] = a * dp[i][i] + d[j];
}else {
dp[i][j] = a * dp[i][j - 1] + d[j];
}
}
}
System.out.printf("%.10f", dp[n][m]);
}
}