【题目链接】​​click here~~  

题目大意】给出一个n个骰子,每个骰子有m个面,给出一个削减值k,投掷一次,所有的骰子点数和要减去k,如果减去的值小于1,则得到的钱也至少是1;要求出他能得到钱的期望值

解题思路】母函数!!,关键在于理解题意思路:(每个点数出现的概率要计算) 具体看代码吧

母函数:

#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
double c1[100005],c2[100005];
int main()
{
int i,j,k,n,m,p;
double sum;
while(cin>>n>>m>>p)
{
if(n==0&&m==0&&p==0) break;
sum=0;
for(i=1; i<=m; i++){//初始化
c1[i]=1; //系数为1
c2[i]=0;
}
for(i=1; i<n; i++){
for(j=1; j<=m*i; j++)//第i个骰子投掷出m面的可能数
for(k=1; k<=m; k++){//总共m面
c2[j+k]+=c1[j];
}
memcpy(c1,c2,sizeof(c2));
memset(c2,0,sizeof(c2));
}
// for(int i=1;i<=m;i++)
// {
// cout<<c1[i]<<" "<<c2[i]<<endl;
// }
for(int i=n; i<=n*m; i++){//n个骰子,每个m面,最小点数为n,最大点数为n*m
if(i>p)
sum+=c1[i]*(double)(i-p);
else
sum+=c1[i];
}
// cout<<"#"<<sum<<"#"<<endl;
printf("%.8lf\n",sum/pow(m,n));
}
return 0;
}

当时比赛最后十几分钟,突然想到一个递推的思路,大致思路是这样:每次从1到m面搜一遍,找出出现1到n*m面的所有可能数,当以骰子个数为0 时结束,且每次计算ans的值


dfs:

#include <bits/stdc++.h>
using namespace std;
double pow(double n,double m)
{
double res=1;
for(int i=1; i<=n; i++)
res*=(m);
return res;
}
double ans;
double n,m,k;
double sum;
void dfs(int a,int b)
{
if(a==0)
{
ans+=(b-k<1?1:(b-k));
return;
}
for(int i=1;i<=m;i++)
{
dfs(a-1,b+i);
}
}
int main()
{
while(cin>>n>>m>>k)
{
ans=0;
if(n==0&&m==0&&k==0) break;
dfs(n,0);
//printf("%lf\n",ans);
double ans2=pow(n,m);
double result=(ans/ans2);
printf("%.8lf\n",result);
}
return 0;
}