【JLOI2013】卡牌遊戲
阿新 • • 發佈:2019-01-04
題面
題解
概率$dp$
設$f[i][j]$表示還剩$i$個人時,第$j$個人獲勝的概率。
邊界$f[1][1] = 1$
轉移:
列舉莊家抽到的卡牌$k$,得到這一輪被淘汰的位置$c$。
可以知道,當$c < j$時,第$j$個人是新的環中的從新莊家數起的第$j-c$個人
當$c > j$時,第$j$個人是新的環中的第$i+j-c$個人。
$$ \therefore f[i][j] \text{+=} \begin{cases} f[i - 1][j - c] / m & (c < j) \\ 0 & (c = j) \\ f[i - 1][i - c + j] / m & (c > j) \end{cases} $$
程式碼
#include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define RG register #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout); #define clear(x, y) memset(x, y, sizeof(x)) inline int read() { int data = 0, w = 1; char ch = getchar(); while(ch != '-' && (!isdigit(ch))) ch = getchar(); if(ch == '-') w = -1, ch = getchar(); while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar(); return data * w; } const int maxn(110); double f[maxn][maxn]; int a[maxn], n, m; int main() { n = read(), m = read(); for(RG int i = 1; i <= m; i++) a[i] = read(); f[1][1] = 1.; for(RG int i = 2; i <= n; i++) for(RG int j = 1; j <= n; j++) for(RG int k = 1; k <= m; k++) { int c = (a[k] % i) ? a[k] % i : i; if(c < j) f[i][j] += f[i - 1][j - c] / m; if(c > j) f[i][j] += f[i - 1][i - c + j] / m; } for(RG int i = 1; i <= n; i++) printf("%.2lf%% ", f[n][i] * 100.); return 0; }