ZOJ 3329 - One Person Game
令f(i)为i分掷色子结束的次数期望,已知f(i|i>N) = 0,那么很容易得到:
因为初始状态是0分,所以答案就是f(0)。我们这里我们采取一个比网上题解更有趣的方法来解出这个式子:
令,那么f(i) = ∑pkf(i+k) + A,我们把左右两端同时除以A,得到f(i)/A = ∑pkf(i+k)/A + 1
然后f(0) = ∑pkf(k) + A, 同时f(0) = (A-1)/p0, 通过整理,那么我们可以解出,然后此时f(0)=(A-1)/p0。
要说编程上需要注意的地方就是不要用1.0f(主要是我手贱),即使是double类型!到时候挂的莫名其妙的还找不到错就悲剧了。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef double DB; DB dp[507], p[37]; int N, maxk; DB f(int i) { if (i > N) return 0; if (~*(int *)&dp[i]) return dp[i]; dp[i] = 1; for(int k=1; k<=maxk; ++k) { if (i+k > N) break; dp[i] += p[k] * f(i+k); } return dp[i]; } int main(void) { int T; scanf("%d", &T); for(int t = 1; t<=T; ++t) { int k1, k2, k3, a, b, c; scanf("%d%d%d%d%d%d%d", &N, &k1, &k2, &k3, &a, &b, &c); memset(dp, -1, sizeof dp); memset(p, 0, sizeof p); DB p0 = 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) { if (i != a || j != b || k != c) p[i+j+k] += p0; } } } maxk = k1+k2+k3; DB s, u; s = u = k1*k2*k3; for(int k=1; k<=maxk; ++k) { if (k > N) break; u -= p[k] * f(k); } printf("%.15f\n", (s/(u-1) - 1)/p0); } return 0; }
2014-11-05 00:36:03 | Accepted | 3329 | C++ | 0 | 176 | esxgx |
This article is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。