筛子游戏
筛子游戏题解
题目大意:
吉吉国王正在玩一款手游,这个手游的规则非常简单。一开始你会得到三个筛子,三个筛子分别有\(k1, k2, k3\)面,也就是说分别可以扔出[1, k1], [1, k2], [1, k3]之间数。一开始的分数为\(0\),每次扔筛子都会扔出\(x, y, z\)三个数,但是这个游戏的特别之处在于每次开局都会给定三个数\(a, b, c\),如果满足\(x = a, y = b, z = c\),那么你的分数就会清零,否则你的分数就会加上\(x + y + z\)。现在吉吉国王想知道需要扔多少次才能使得他的分数大于\(n\)。
题目分析:
先令\(k = k1 + k2 + k3\),首先我们是可以预处理出来[3, K]每一步可能增加数值的概率,对于0情况特殊判断,我们假定dp[i]代表的含义为当前数值为i时,他还需要扔的期望数,使得他的分数大于n,从而我们可以推出一个状态转移方程$dp[i] = $$\sum$dp[i + k] * p[i + k] + \(dp[0] * p[0]\) + \(1\),而我们知道dp[0]是我们要求的答案,通过这个式子我们是无法直接得到答案的,所以我们令\(dp[i] = A[i] * dp[0] + B[i]\),将该式,带入进求和符号中的式子中,将有关\(dp[0]\)的部分,放在一起,可化简为,$dp[i] = $ (\(\sum\)A[i + k] * p[k] + \(p[0]\)) * \(dp[0]\) + \(\sum\)B[i + k] * p[k] + 1, 可以发现这和我们开始假定的式子很像,所以我们可以认为$A[i] = $$\sum$A[i + k] * p[k] + \(p[0]\), $B[i] = $ \(\sum\) B[i + k] * p[k] + 1. 而我们的答案$dp[0] = $ $B[0] / $$(1 - A[0])$.
代码:
#include<bits/stdc++.h>
using namespace std;
double dp[30004];
double A[30004];
double B[30004];
int main(){
int n, k1, k2, k3, a, b, c;
cin >> n >> k1 >> k2 >> k3 >> a >> b >> c;
for (int i = 1; i <= k1; ++i){
for (int j = 1; j <= k2; ++j){
for (int k = 1; k <= k3; ++k3){
if (i == a && j == b && k == c){
dp[0]++;
}else{
dp[i + j + k] ++;
}
}
}
}
int K = i + j + k;
for (int i = 0; i <= K; ++i){
dp[i] = dp[i] / (K * 1.0);
}
for (int i = n; i >= 0; --i){
A[i] += dp[0];
B[i] += 1;
for (int j = 3; j <= K; ++j){
if (i + j > n) continue;
A[i] += A[i + j] * dp[j];
B[i] += B[i + j] * dp[j];
}
}
double ans = 0;
ans = b[0] / (1 - A[0]);
printf("%.6lf",ans);
}