这题最开始是用 (n^{4})的算法水过的,之后才想出的(n^{3})正解。首先,(n^{4}) 应该是很容易想到的:设状态 (f[i][j][k]) 为有 (i) 个人,庄家为 (j) 号人时,第 (k) 个人胜出的概率。这样,只需要去掉本轮淘汰的人,加上 (i - 1) 个人时该人胜出的概率即可。
#include <bits/stdc++.h> using namespace std; #define maxn 55 #define db double int n, m, a[maxn]; db P, f[maxn][maxn][maxn]; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * k; } int main() { n = read(), m = read(); P = (db) 1 / (db) m; for(int i = 1; i <= m; i ++) a[i] = read(); f[1][1][1] = 1; for(int i = 2; i <= n; i ++) for(int j = 1; j <= i; j ++) for(int k = 1; k <= i; k ++) { for(int x = 1; x <= m; x ++) { int t = (a[x] + j - 1) % i, T = t + 1, K = k; if(!t) t = i; if(t == k) continue; if(K > t) K -= 1; if(T > t) T -= 1; f[i][j][k] += P * f[i - 1][T][K]; } } for(int i = 1; i <= n; i ++) printf("%.2lf%% ", f[n][1][i] * 100); return 0; }
但是这题还有更优的做法。我们再看一看自己所设置的状态,详加思考就会发现:其实第二维是不必要的。谁做庄家实际上都是一个相对的概念,我们可以强制让(1) 号为庄家,这样只需要在新的环上找出原来编号为 (k) 的人对应的新编号 (k') 并加上其概率就好啦。
#include <bits/stdc++.h> using namespace std; #define maxn 55 #define db double int n, m, a[maxn]; db P, f[maxn][maxn]; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * k; } int main() { n = read(), m = read(); P = (db) 1 / (db) m; for(int i = 1; i <= m; i ++) a[i] = read(); f[1][1] = 1; for(int i = 2; i <= n; i ++) for(int k = 1; k <= i; k ++) for(int x = 1; x <= m; x ++) { int t = a[x] % i, T = t + 1, K = k; if(!t) t = i; if(t == k) continue; if(K > t) K -= 1; if(T > t) T -= 1; if(K < T) K = (i - T + K); else if(K > T) K = K - T + 1; else K = 1; f[i][k] += P * f[i - 1][K]; } for(int i = 1; i <= n; i ++) printf("%.2lf%% ", f[n][i] * 100); return 0; }