题目描述
Alice and Bob are playing a simple game. They line up a row of n identical coins, all with the heads facing down onto the table and the tails upward.
For exactly m 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.
输入
The input has several test cases and the first line contains the integer t (1 ≤ t ≤ 1000) which is the total number of cases.
For each case, a line contains three space-separated integers n, m (1 ≤ n, m ≤ 100) and k (1 ≤ k ≤ n).
输出
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
来源/分类
原来还有概率dp这种东西.......
题意:
给出n个反着的硬币,m次操作,每次可以任选k个硬币抛向空中,每个落下来 正反的概率各占一半。
问,在尽量使硬币为正的策略下,最后的正面期望值。
分析:
想了很久的规律....丝毫没有考虑到dp...
首先,最优策略就是:每次选取k个的时候,我们先选反面朝上的硬币,如果不够,再选正面朝上的
因为每次的翻转只跟上次的翻转情况有关,所以我们可以推导一下递推式dp
很容易想到dp[i][j] 表示 翻转完第i次时,j个硬币正面朝上的概率
递推式:我们得到了dp[i][j] 第 i 次翻转后有 j 个正面朝上,这时候我们进行第 i+1 次翻转,会遇到两种情况:
- j+k<=n: 即我们可以选k个反面朝上的硬币操作,然后可以求得这k个硬币中朝上的个数 t 的概率p,那么dp[i+1][j+t] = dp[i][j]*p; p = C(k,t)* (1/2)^k
- j+k > n: 即需要选择 tp=(j+k-n) 个正面朝上的硬币进行翻转,所以第i+1次翻转后确定的正面朝上的个数为 j-tp 个,然后考虑k个刚翻转的正面朝上的个数t 的概率p,p还是C(k,t)* (1/2)^k;所以此时递推式为 dp[i+1][j-tp+t] = dp[i][j]*p;
而且:对于给定的k,t 的概率p恒为 C(k,t)* (1/2)^k,所以可以先预处理这一部分
AC代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fLL
#define pi acos(-1.0)
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
ll qpow(ll x, ll y, ll mod){ll s=1;while(y){if(y&1)s=s*x%mod;x=x*x%mod;y>>=1;}return s;}
int n, m, k;
double dp[105][105];
double C[105][105], p[105];
void init()
{
C[0][0] = 1; p[0] = 1;
for(int i=1;i<105;i++)
{
C[i][0]=1;
p[i]=p[i-1]*0.5;
for(int j=1;j<=i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
for(int i=0;i<=k;i++) C[k][i]*=p[k];
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d%d", &n, &m, &k);
init(); ms(dp, 0);
dp[0][0] = 1;
for(int i=0;i<m;i++)
{
for(int j=0;j<=n;j++)
{
if(j+k<=n)
{
for(int t=0;t<=k;t++)
dp[i+1][j+t] += dp[i][j]*C[k][t];
}
else
{
int tp=j+k-n;
for(int t=0;t<=k;t++)
dp[i+1][j+t-tp] += dp[i][j]*C[k][t];
}
}
}
double ans = 0;
for(int i=1; i<=n; i++)
ans += i*dp[m][i];
printf("%.3f\n", ans);
}
return 0;
}