题目大意:
就是现在有一个游戏初始的时候分值为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; }