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

[JLOI2013]卡牌游戏

时间:2018-11-02 00:12:59      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:代码   --   include   getc   read   \n   设定   name   自己   

传送门

这个题一开始不会转移了……因为自己状态设定的不对。

应该参考一下约瑟夫问题的操作,设dp[i][j]表示在有i个人的时候从庄家开始数第j个人的获胜概率。这样的话,我们只要枚举每张卡牌,这样的话,每个人获胜的概率就能由有i-1个人的时候推出来,因为其实淘汰一个人就是相当于把队列向前移动几位,但是胜利者并不会改变。

抽到每张卡的概率相同,所以我们就能得到DP方程:

dp[i][j] += (dp[i-1][(j-c[k] + i)%i]) / m.

这样直接递推一下就可以啦,代码很短。注意最后答案要先乘以100.

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)

using namespace std;
typedef long long ll;
const int M = 10005;
const ll INF = 1000000009;
const int mod = 9397;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)
    {
    if(ch == -) op = -1;
    ch = getchar();
    }
    while(ch >= 0 && ch <= 9)
    {
    ans *= 10;
    ans += ch - 0;
    ch = getchar();
    }
    return ans * op;
}

int a[M],n,m;
double dp[1005][1005];

int main()
{
   n = read(),m = read();
   rep(i,1,m) a[i] = read();
   dp[1][1] = 1.0;
   rep(i,2,n)
   rep(j,1,i)
   rep(k,1,m)
   {
      int c = (a[k] % i) ? a[k] % i : i;
      if(c > j) dp[i][j] += dp[i-1][i-c+j] / (double)m * 1.0;
      else if(c < j) dp[i][j] += dp[i-1][j-c] / (double)m * 1.0;
   }
   rep(i,1,n) printf("%.2lf%% ",dp[n][i] * 100.0);enter;
   return 0;
}

 

[JLOI2013]卡牌游戏

标签:代码   --   include   getc   read   \n   设定   name   自己   

原文地址:https://www.cnblogs.com/captain1/p/9892848.html

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