洛谷 2059 [JLOI2013] 卡牌游戏

1 篇文章 0 订阅

题目


状态定义:


由于每一次会处决一个人,只剩下一个人,那么最后剩下的那个人一定是胜率 100%的,所以剩下两个人的胜率可以由剩下一个人的胜率转移过来 。状态定义不是显然,不如我们先看一下如果将状态定义为:

dp [ i ] = dp [ i - 1 ] + somework;

其中,dp [ i ] 的意义是剩下 i 个人的胜率 …… 欸,到底是谁的胜率呢?看来不是很好转移 ……

不如加一维,重新定义 dp [ i ]:

dp [ i ] [ j ] = dp [ i - 1 ] [ j ] + somework;

其中 dp [ i ] [ j ] 的意义是剩下 i 个人中的从庄家开始数的第 j 个人的胜率,看样子还行 。


尝试转移:


如何转移方程呢?

首先我们会枚举 j,也就是这次从庄家数第几个玩家,如果我们要把方程转移的话,必须知道这个人在上一个状态(剩下 i - 1 个人的状态)所在的位置 。

假设这次抽到了牌号为 X 的牌,那么显然它所决定要处决的人的位置在 ( a [ k ] % i ) 的位置上;这里有一个小细节,有可能会 % 成 0,所以当 % 成 0 的时候说明即将处决第 i 个人,所以直接特判一下就好了 。

但是处决的位置有两种:

令 Y = ( a [ k ] % i );

如果 Y > j:


发现这一状态(i)的第 j 个人是上一个状态的第 (i - Y + j)个人;

如果 Y > j:


发现这一状态(i)的第 j 个人是上一个状态的第 (j - Y)个人;

(上图和下图的顺序反了一下,不过不影响)

确定了位置,那么这次的第 j 个人的胜率就可以由上一个 j' 推过来,当然,这只是一种抽牌方式,所以要乘以概率 1/m,然而这也不只是唯一的一种获胜(避开处决)的方式(因为抽的牌可能不同),而且多种方式并列产生胜率,所以,加法原理 ——


得到 Dp 方程:

Y > j: dp [ i ] [ j ] += dp [ i - 1 ] [ i - c + j ] / m ;

Y < j: dp [ i ] [ j ] += dp [ i - 1 ] [ j - c ] / m ;


代码:


#include <bits/stdc++.h>

const  int  N = 50 + 1  ;

//using  namespace  std ;

double  dp [ N ] [ N ] ;
int  n , m , a [ N ] ;

int  main ( ) {
    
    scanf ( "%d%d" , & n , & m ) ;
 	for ( int  i = 1 ; i <= m ; i ++ )
 		scanf ( "%d" , & a [ i ] ) ;
    dp [ 1 ] [ 1 ] = 1 ; 
    for ( int  i = 2 ; i <= n ; i ++ ) {
        for ( int  j = 1 ; j <= i ; j ++ )
            for ( int  k = 1 ; k <= m ; k ++ ) {
                int  c = ( a [ k ] % i ) == 0 ? i : a [ k ] % i ;
                if ( c > j ) {
                    dp [ i ] [ j ] += dp [ i - 1 ] [ i - c + j ] / m ;
                } 
                else {
                    dp [ i ] [ j ] += dp [ i - 1 ] [ j - c ] / m ; 
                }
        }
    }
    for ( int  i = 1 ; i <= n ; i ++ )
        printf ( "%.2lf" , 100 * dp [ n ] [ i ] ) , printf ( "%% " ) ;
    
    return  0 ;
}


坚持取消后摇!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值