题意
有三个色子,每个色子有ki面,分别代表1-ki。
每次你丢三个色子,如果分别摇到a, b, c,则积分器归零, 否则积分器加a+b+c。
积分器大于n时游戏结束。问期望丢的次数。
题解
设d[i] 为当前积分器为i时距离游戏结束还需要丢的期望次数。
d[i] = + d[0] * p[0] + 1.
p[i]为摇到的和为i的概率。
显然dp方程有环。
即dp[i]既由大于i的dp[i+j]又由小于i的dp[0]转移过来。
现在我们考虑消掉dp[i+j]。
我们设d[i] = A[i] * d[0] + B[0]。
让d[i+j] = A[i+j] * d[0] + B[i+j]代入原方程,
得到
化简得到
又有
得到
d[0]就是结果
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 2e6 + 5;
double A[555], B[555];
double p[555];
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int T;
cin >> T;
while(T--) {
int n, k1, k2, k3, a, b, c;
scanf("%d %d %d %d %d %d %d", &n, &k1, &k2, &k3, &a, &b, &c);
memset(p, 0, sizeof(p));
for(int i = 1; i <= k1; i++)
for(int j = 1; j <= k2; j++)
for(int k = 1; k <= k3; k++) {
if(i == a && j == b && k == c) continue;
p[i+j+k] += 1./(k1*k2*k3);
}
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
for(int i = n; i >= 0; i--) {
A[i] = 1./(k1*k2*k3); B[i] = 1;
for(int j = 1; j <= k1+k2+k3; j++) {
A[i] += p[j] * (A[i + j]);
B[i] += p[j] * (B[i + j]);
}
}
printf("%.15lf\n", B[0] / (1.0 - A[0]));
}
return 0;
}