题目大意:
就是现在有一个游戏初始的时候分值为0,现在有3个骰子,每次同时掷骰子,当三个骰子依此出现的点数是a,b,c时将得分重新变为0,否则就加上这个点数和,三个骰子的最大点数分别是K1, K2, K3并且出现1~Ki的可能性是1/Ki, (1 <= i <= 3)
现在要求分数不低于n,问最少要掷多少次骰子, 求这个次数的期望。
大致思路:
思路见代码注释
代码如下:
Result : Accepted Memory : 280 KB Time : 0 ms
/*
* Author: Gatevin
* Created Time: 2014/11/30 18:01:38
* File Name: Asuna.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
/*
* 首先如果用E[i]表示当前分数为i时还需要的步数的期望, 则答案即为E[0]
* 不难发现E[i > n] = 0;
* 而且对于E[i < n], E[i] = E[i + 3]*p[3] + E[i + 4]*p[4] + ... + E[i + K1 + K2 + K3]*p[K1 + K2 + K3] + E[0]*p[0] + 1;(0 <= i <= n)
* 其中p[j] 表示掷骰子之后加的分数,p[0]表示重置为0的概率
* 不难发现这个方程有环, 但是由于一共有 n + 1 个未知数(E[0 ~ n])且有 n + 1个方程,矩阵的秩满,可解
* 在仔细观察,由于E[i > n] = 0, E[n] = E[0]*p[0] + 1, E[n - 1] = E[0]*p[0] + 1, ... E[n - 4] = E[n - 3]*p[3] + E[0]*p[0] + 1....
* 由于E[n, n -1, n - 2, n - 3, n - 4..]都是A*E[0] + B的形式,在递推时 E[k] = A[k]*E[0] + B[k]也一定满足(一次的线性关系)
* 并且设E[i] = A[i]*E[0] + B[i]之后,由于 E[i] 满足的递推式有
* A[i]*E[0] + B[i] = (A[i + 3]*E[0] + B[i + 3])*p[3] + .... + (A[i + K1 + K2 + K3]*E[0] + B[i + K1 + K2 + K3])*p[i + K1 + K2 + K3] + E[0]*p[0] + 1
* 于是, A[i] = A[i + 3]*p[3] + A[i + 4]*p[4] + .. + A[i + K1 + K2 + K3]*p[K1 + K2 + K3] + p[0];
B[i] = B[i + 3]*p[3] + B[i + 4]*p[4] + .. + B[i + K1 + K2 + K3]*p[K1 + K2 + K3] + 1;
* A[i > n] = B[i > n] = 0;
* 于是可以递推算出A[0], B[0];
* 由于A[0]*E[0] + B[0] = E[0]
* E[0] = B[0]/(1 - A[0]);
*/
double A[520], B[520];
int k1, k2, k3, t, n, a, b, c;
double p[20];
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d %d %d %d %d %d %d", &n, &k1, &k2, &k3, &a, &b, &c);
memset(p, 0, sizeof(p));
p[0] = 1.0/(k1*k2*k3);
for(int i = 1; i <= k1; i++)
for(int j = 1; j <= k2; j++)
for(int k = 1; k <= k3; k++)
p[i + j + k] += p[0];
p[a + b + c] -= p[0];
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
for(int i = n; i >= 0; i--)
{
for(int up = 3; up <= k1 + k2 + k3; up++)
{
A[i] += A[i + up]*p[up];
B[i] += B[i + up]*p[up];
}
A[i] += p[0];
B[i] += 1;
}
double ans = B[0]/(1 - A[0]);
printf("%.10f\n", ans);
}
return 0;
}