洛谷传送门
BZOJ传送门
题目描述
N N N个人坐成一圈玩游戏。一开始我们把所有玩家按顺时针从 1 1 1到 N N N编号。首先第一回合是玩家 1 1 1作为庄家。每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为 X X X,则庄家首先把卡片上的数字向所有玩家展示,然后按顺时针从庄家位置数第 X X X个人将被处决即退出游戏。然后卡片将会被放回卡牌堆里并重新洗牌。被处决的人按顺时针的下一个人将会作为下一轮的庄家。那么经过 N − 1 N-1 N−1轮后最后只会剩下一个人,即为本次游戏的胜者。现在你预先知道了总共有 M M M张卡片,也知道每张卡片上的数字。现在你需要确定每个玩家胜出的概率。
这里有一个简单的例子:
例如一共有 4 4 4个玩家,有四张卡片分别写着 3 , 4 , 5 , 6. 3,4,5,6. 3,4,5,6.
第一回合,庄家是玩家 1 1 1,假设他选择了一张写着数字 5 5 5的卡片。那么按顺时针数 1 , 2 , 3 , 4 , 1 1,2,3,4,1 1,2,3,4,1,最后玩家 1 1 1被踢出游戏。
第二回合,庄家就是玩家 1 1 1的下一个人,即玩家 2 2 2.假设玩家 2 2 2这次选择了一张数字 6 6 6,那么 2 , 3 , 4 , 2 , 3 , 4 2,3,4,2,3,4 2,3,4,2,3,4,玩家 4 4 4被踢出游戏。
第三回合,玩家 2 2 2再一次成为庄家。如果这一次玩家 2 2 2再次选了 6 6 6,则玩家 3 3 3被踢出游戏,最后的胜者就是玩家 2 2 2.
输入输出格式
输入格式:
第一行包括两个整数N,M分别表示玩家个数和卡牌总数。
接下来一行是包含M个整数,分别给出每张卡片上写的数字。
输出格式:
输出一行包含N个百分比形式给出的实数,四舍五入到两位小数。分别给出从玩家1到玩家N的胜出概率,每个概率之间用空格隔开,最后不要有空格。
输入输出样例
输入样例#1:
5 5
2 3 5 7 11
输出样例#1:
22.72% 17.12% 15.36% 25.44% 19.36%
输入样例#2:
4 4
3 4 5 6
输出样例#2:
25.00% 25.00% 25.00% 25.00%
说明
对于 30 % 30\% 30%的数据,有 1 ≤ N ≤ 10 1\le N\le 10 1≤N≤10
对于 50 % 50\% 50%的数据,有 1 ≤ N ≤ 30 1\le N\le 30 1≤N≤30
对于 100 % 100\% 100%的数据,有 1 ≤ N ≤ 50 1 ≤ M ≤ 50 1\le N\le 50\ 1\le M\le 50 1≤N≤50 1≤M≤50 $1\le 每 张 卡 片 上 的 数 字 每张卡片上的数字 每张卡片上的数字\le 50$
解题分析
如果完整记录剩 i i i个人的时候剩下的人的编号, 显然要 M L E + T L E MLE+TLE MLE+TLE。
我们就只记录剩下 i i i个人的时候第 i i i个人的胜率, 倒推回有 n n n个人的时候就行了。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define db double
#define MX 55
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
db dp[MX][MX];
int to[MX];
int n, m, tar;
int main(void)
{
in(n), in(m);
for (R int i = 1; i <= m; ++i) in(to[i]);
for (R int i = 1; i <= n; ++i) dp[1][i] = 1;
for (R int i = 2; i <= n; ++i)
for (R int j = 1; j <= i; ++j)
for (R int k = 1; k <= m; ++k)
{
tar = (to[k] - 1) % i + 1;
if(tar > j) dp[i][j] += dp[i - 1][j - tar + i] / m;
else if(tar < j) dp[i][j] += dp[i - 1][j - tar] / m;
//tar=j的时候j被淘汰了, 就不加上了
}
for (R int i = 1; i <= n; ++i) printf("%.2lf%% ", dp[n][i] * 100);
}