一道比较简单的概率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 e 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;
}