bzoj 3191
题意:见上。
根据题目,我们可以从终态入手。考虑什么状态下概率已定。(期望概率题入手套路)
这里可以发现只有一个人时,必定他会胜利,所以我们可以按照「人数」划分阶段。
那么可以设$dp(i,j)$为有$i$个人时,庄家开始数第$j$个人胜利的概率。(也可以设更加明显的三维状态)
那么$dp(i-1)$可以转移到$dp(i)$
从$i-1$到$i$, $i$下$j$的这个人是不动的。考虑$i$时淘汰一个人,即枚举$a[k]$使得$c=a[k] \mod i$,$c-1$是淘汰的人相对当前$i$庄家的位置。
然后因为淘汰了一个人庄家就是这个人的下一个,那么考虑两种情况
第一种,庄家跑不到$j$的后面,那么这时$dp(i,j)=\frac{dp(i-1,j-c)}m$,画图可知
第二种,庄家会跑到$j$的后面,那么这时$dp(i,j)=\frac{dp(i-1,j+(i-c))}m$,画图可知
那么最后$dp(n)$即为答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<vector>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
int n, m, a[55];
db dp[55][55];
void clean() {
ms(dp, 0);
}
int solve() {
clean();
cin >> n >> m;
for (int i = 1; i <= m; ++i) cin >> a[i];
dp[1][1] = 1.0;
for (int i = 2; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
for (int k = 1; k <= m; ++k) {
int c = a[k] % i;
if (!c) c = i;
if (c < j)
dp[i][j] += dp[i - 1][j - c] / m;
else if (c > j)
dp[i][j] += dp[i - 1][j + (i - c)] / m;
}
}
}
for (int i = 1; i <= n; ++i) {
printf("%.2f%% ", dp[n][i] * 100.0);
}
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}