[JLOI2013]卡牌游戏

传送门

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

应该参考一下约瑟夫问题的操作,设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;
}
复制代码

 

posted @   CaptainLi  阅读(187)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示