Alice and Bob are playing a simple game. They line up a row of nnn identical coins, all with the heads facing down onto the table and the tails upward.
For exactly mmm times they select any k of the coins and toss them into the air, replacing each of them either heads-up or heads-down with the same possibility. Their purpose is to gain as many coins heads-up as they can.
Input
The input has several test cases and the first line contains the integer t which is the total number of cases.
For each case, a line contains three space-separated integers n, m and k.
Output
For each test case, output the expected number of coins heads-up which you could have at the end under the optimal strategy, as a real number with the precision of 3 digits.
样例输入
6 2 1 1 2 3 1 5 4 3 6 2 3 6 100 1 6 100 2
样例输出
0.500 1.250 3.479 3.000 5.500 5.000
题目来源
题意:
给你n个一开始朝下的硬币,然后让抛硬币,抛一次硬币,正反面朝上的概率相等。让你抛m次,每次抛k个,
一次里面抛的硬币互相独立,但不能是重复的硬币,问你,每次采取最佳策略后,朝上面的硬币的数量的期望是?
解析:
一开始做,推了半天公式,发现推出来的公式算出来的答案和样例不对........
上网搜了题解,说公式推不出来,上概率dp.......一看n,m范围.....还真行
这里主要麻烦的是,当情况①朝下的硬币数量<k时你就不得不拿朝上的硬币去抛。
这里用p表示每次抛的硬币的个数
dp[i][j]=扔了i次,j个硬币朝上的概率
那么我们就先考虑朝下的硬币数量>p的情况
情况②然后是朝下的硬币数量<p的情况
先看一组例子:n=6,p=4,k=3对dp[i][5]有贡献的有dp[i-1][2](情况①),dp[i-1][3](情况②),dp[i-1][4](情况②)....dp[i-1][6](情况②)
而n=6,p=4,k=4对dp[i][5]有贡献的只有dp[i-1][1](情况②)
从这组样例中我们可以看出对于一个dp[i][j],只有一个特定的k=j+p-n,才会进入情况②,并且一旦进入情况②,
dp[i][w] 都会对其贡献。这个可以通过公式推出来的,因为你发现后面推公式w这个变量被消掉了
=>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1e2+10;
double C[MAXN][MAXN],two[MAXN];
double dp[MAXN][MAXN];
void init()
{
two[0]=1;
for(int i=1;i<MAXN;i++)
two[i]=two[i-1]/2;
C[0][0]=1;C[0][1]=0;
for(int i=1; i<MAXN ;i++)
for(int j=0; j<=i ;j++)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
int main()
{
int t;
scanf("%d",&t);
int n,m,p;
init();
while(t--)
{
scanf("%d%d%d",&n,&m,&p);
dp[0][0]=1;
for(int i=1;i<=m;i++)
for(int j=0;j<=n;j++)
{
dp[i][j]=0;
for(int k=0;k<=p;k++)
{
if(j<k) continue;
double ans=C[p][k]*two[p];
if(n-(j-k)>=p)
{
dp[i][j]+=dp[i-1][j-k]*ans;
}
}
double ans=C[p][j+p-n]*two[p];
for(int k=n-p+1;k<=n;k++)
{
dp[i][j]+=dp[i-1][k]*ans;
}
}
double res=0;
for(int i=1;i<=n;i++)
{
res+=dp[m][i]*i;
}
printf("%.3lf\n",res);
}
return 0;
}