码迷,mamicode.com
首页 > 其他好文 > 详细

[JLOI2013] 卡牌游戏

时间:2018-10-29 10:28:13      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:define   std   clu   pac   pre   time   http   删除   algo   

题目链接:https://www.luogu.org/problemnew/show/P2059

概率DP。

我们设计状态为\(sum[i][j]\)表示还剩下i个人的时候,从庄家开始数第\(j\)个人获胜的概率(不包括庄家)。

之后就是状态转移了。我们先考虑顺推,但是发现不太可做,因为还有删除节点的情况存在。删除总没有添加好做,所以我们考虑倒着推。

首先我们要知道——如果有情况A有m的概率发生,且它们有n的概率直接转换成情况B,那么B情况发生的概率可加上\(m\times n\)

我们定义庄家的位置为:\(pos\)

我们定义当前的淘汰者的位置为:\(pos+c\)

\(j\)的位置为:\(pos+j\)

那么显然,\(j>c\)的时候,\(j\)的位置是\(i-1\)个人的新环中新庄家开始数的第\(j-c-1\)个人(不包括庄家)

\(j==c\)的时候,第\(j\)个人一定会输,所以不累加胜率。

\(j<c\)的时候,第\(j\)个人的位置是\(i-1\)人新环中新庄家开始数的第\(i-(pos+c-pos-j)-1=i-c+j-1\)个人。(不包括庄家)

初始化:很显然的,当还剩一个人的时候,他一定是必胜的。所以\(sum[1][0]=1.0\)

所以状态转移方程为:

if(j>c)
    sum[i][j]+=sum[i-1][j-c-1]/m;
else if(j<c)
    sum[i][j]+=sum[i-1][i-c+j-1]/m;

完整代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 55
using namespace std;
int n,m;
int a[MAXN];
double sum[MAXN][MAXN];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]),a[i]--;
    sum[1][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<i;j++)
        {
            for(int k=1;k<=m;k++)
            {
                int c=(a[k]%i==0)?i:a[k]%i;
                if(j>c) sum[i][j]+=sum[i-1][j-c-1]/m;
                else if(j<c) sum[i][j]+=sum[i-1][i-c+j-1]/m;
            }
        }
    }
    for(int i=1;i<=n;i++)
        printf("%.2lf%% ",sum[n][i-1]*100);
    return 0;
}

[JLOI2013] 卡牌游戏

标签:define   std   clu   pac   pre   time   http   删除   algo   

原文地址:https://www.cnblogs.com/fengxunling/p/9867038.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!