Luogu P2059 [JLOI2013]卡牌游戏

一道比较简单的概率DP

首先看到这种题目和数据范围,就要毫不犹豫地列DP方程:

我们令\(f_{i,j}\)表示还剩下i个人时编号为j的人的胜率,那么首先我们可以知道边界条件\(f_{1,1}=1\)

然后我们考虑多一个人的情况会是怎样。

我们先枚举还剩下\(i(2<=i<=n)\)个人,然后对于每一个人\(j(1<=j<=i)\)(注意这里是的\(j\)指的是在这\(i\)个人里的编号

然后枚举卡片\(k\),对于上面的数字\(a_k\)我们先得出这一轮会被淘汰的人的编号\(x\)。然后如果\(x\ne j\)那么就有转移:

  • \(f_{i,j}+=\frac{f_{i-1,i-x+j}}{m}(x>j)\)
  • \(f_{i,j}+=\frac{f_{i-1,j-x}}{m}(x<j)\)

然后就可以A了

CODE

#include<cstdio>
using namespace std;
const int N=55;
int a[N],n,m;
double f[N][N];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch=tc();
    while (ch<'0'||ch>'9') ch=tc();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j,k; read(n); read(m);
    for (i=1;i<=m;++i)
    read(a[i]); f[1][1]=1.0;
    for (i=2;i<=n;++i)
    for (j=1;j<=i;++j)
    for (k=1;k<=m;++k)
    {
        int x=a[k]%i?a[k]%i:i;
        if (x>j) f[i][j]+=(double)f[i-1][i-x+j]/m;
        if (x<j) f[i][j]+=(double)f[i-1][j-x]/m;
    }
    for (i=1;i<=n;++i)
    printf("%.2lf%% ",f[n][i]*100.0);
    return 0;
}
posted @ 2018-06-07 13:04  空気力学の詩  阅读(159)  评论(0编辑  收藏  举报