Coins I(ICPC2017 Urumqi)
https://www.jisuanke.com/contest/1409/challenges
题目描述
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.
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 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
题意:n个反面朝上的硬币,m次抛,每次抛硬币从n个硬币中选k个,问最优情况下,正面朝上的期望
题解:显然是一道概率dp 的题,因为这道题说的是最优,很明显每次选的k枚硬币尽量都选反面朝上的
dp[i][j]表示 第i次抛硬币中j个正面朝上的概率,对于抛k枚硬币,c枚朝上的组合有 C(k,c)种
对于抛硬币正和反的概率都是0.5,所以抛k次概率为0.5^k
我们枚举抛k 枚硬币出现正面朝上的个数c,dp[i+1][x] = dp[i][j]*C(k,c)*0.5^k (x为当前状态所有硬币正面朝上的个数)
当某一状态中剩余反面朝上的个数 >= k,则 全抛反面朝上的硬币 即x = c,否则,把所有反面朝上的硬币 + 一些正面朝上的硬币 一起抛,没参与抛的正面朝上的硬币数为 n - k, 即 x = n - k + c
AC code:
#include <bits/stdc++.h> using namespace std; const int N = 100 + 10; double dp[N][N],C[N][N],p[N]; int main() { int t,n,m,k; scanf("%d",&t); C[0][0] = 1; p[0] = 1; for(int i = 1;i < N;i++) { p[i] =p[i-1]*0.5; for(int j = 0;j <= i;j++) C[i][j] = (j == 0?1:(C[i-1][j]+C[i-1][j-1])); } while(t--) { scanf("%d%d%d",&n,&m,&k); memset(dp,0,sizeof(dp)); dp[0][0] = 1; for(int i = 0;i < m;i++) for(int j = 0;j <= n;j++) for(int c = 0;c <= k;c++) { if(n - j >= k) dp[i+1][j+c] += dp[i][j]*C[k][c]*p[k]; else dp[i+1][n-k+c] += dp[i][j]*C[k][c]*p[k]; } double ans = 0; for(int i = 0;i <= n;i++) ans += dp[m][i]*i; printf("%.3lf\n",ans); } return 0; }