列表

详情


NC20135. [JLOI2013]卡牌游戏

描述

N个人坐成一圈玩游戏。一开始我们把所有玩家按顺时针从1到N编号。
首先第一回合是玩家1作为庄家。每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为X,则庄家首先把卡片上的数字向所有玩家展示,然后按顺时针从庄家位置数第X个人将被处决即退出游戏。然后卡片将会被放回卡牌堆里并重新洗牌。被处决的人按顺时针的下一个人将会作为下一轮的庄家。那么经过N-1轮后最后只会剩下一个人,即为本次游戏的胜者。
现在你预先知道了总共有M张卡片,也知道每张卡片上的数字。现在你需要确定每个玩家胜出的概率。 
这里有一个简单的例子: 例如一共有4个玩家,有四张卡片分别写着3,4,5,6. 
第一回合,庄家是玩家1,假设他选择了一张写着数字5的卡片。那么按顺时针数1,2,3,4,1,最后玩家1被踢出游戏。
第二回合,庄家就是玩家1的下一个人,即玩家2.假设玩家2这次选择了一张数字6,那么2,3,4,2,3,4,玩家4被踢出游戏。
第三回合,玩家2再一次成为庄家。如果这一次玩家2再次选了6,则玩家3被踢出游戏,最后的胜者就是玩家2.  

输入描述

第一行包括两个整数N,M分别表示玩家个数和卡牌总数。
接下来一行是包含M个整数,分别给出每张卡片上写的数字。

输出描述

输出一行包含N个百分比形式给出的实数,四舍五入到两位小数。
分别给出从玩家1到玩家N的胜出概率,每个概率之间用空格隔开,最后不要有空格。

示例1

输入:

5 5
2 3 5 7 11

输出:

22.72% 17.12% 15.36% 25.44% 19.36%

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 4ms, 内存消耗: 488K, 提交时间: 2022-08-02 20:03:36

#include<bits/stdc++.h>
using namespace std;
const int maxn=50+5;
typedef long long ll;
double dp[maxn][maxn];
int a[maxn];
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d",&a[i]);
	dp[1][1]=1.0;
	for(int i=2;i<=n;i++)
		for(int j=1;j<=i;j++)
			for(int k=1;k<=m;k++)
				dp[i][j]+=dp[i-1][((i+j-a[k]%i)+i)%i]/(1.0*m);
	for(int i=1;i<=n;i++)printf("%.2lf%% ",dp[n][i]*100.0);
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 5ms, 内存消耗: 740K, 提交时间: 2020-03-30 15:48:29

#include<bits/stdc++.h>
using namespace std;

double dp[100][100];
int a[100];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++) cin>>a[i];
	dp[1][1]=1;
	for(int i=2;i<=n;i++)
	{
		for(int k=1;k<=m;k++)
		{
			for(int j=1;j<=i;j++)
			{
				int p=a[k]%i;
				dp[i][j]+=dp[i-1][(j-p-1+i)%i+1]/m;
			}
		}
	}
	for(int i=1;i<=n;i++) 
	{
		printf("%.2f%% ",dp[n][i]*100);
	}
	cout<<endl;
	return 0;
}

上一题