Coins
时间限制: 1 Sec 内存限制: 128 MB
提交: 105 解决: 62
[提交] [状态] [讨论版] [命题人:admin]
题目描述
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
题意:
![](/qrcode.jpg)
一开始有 n 枚硬币反面朝上,有 m 次机会,每次机会必须选取 k 枚硬币上抛,问在最优策略下,最后能有多少枚硬币正面朝上。
题解:
借鉴的大神的思路
用dp[i][j]表示第i次上抛结束后j枚硬币朝上的概率;
首先最优策略是第 i 次上抛结束后有 j 枚硬币一定正面朝上,则第i+1次选取k枚硬币时
1.如果 j + k <= n,也就是此时反面朝上的硬币数量 >= k,那么我们此时肯定要从反面朝上的硬币中选,dp[i+1][j+t]就表示第i+1次结束以后,j+t枚硬币正面朝上的概率,dp[i+1][j+t] += dp[i][j] * C(k,t) / (2^k);
2.如果j + k > n,也就是反面朝上的硬币数量 <k,令 tt = j + k - n,也就是说要从已经正面朝上的硬币中选取tt枚硬币上抛,从反面朝上的硬币中选取k - tt枚硬币上抛,则i+1次上抛硬币结束后一定正面朝上的硬币数量为 j - tt,因此i+1次后,dp[i+1][j - tt + t] = dp[i][j] * C(k,t) / (2^k);
PS 概率DP中数学期望 P=Σ每一种状态*对应的概率
正常的DP代码是逆向推的,而这个是正向推的,更好理解
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#define INF 0x3f3f3f3f
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e6+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
#define gcd(a,b) __gcd(a,b)
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
const ll maxn = 105;
double dp[maxn][maxn];
double c[maxn][maxn];
int n,m,k;
void init()
{
double temp=1.0;
for(int i=1;i<=k;i++)temp*=2.0;
c[k][0]=1;
for(int i=1;i<=k;i++)c[k][i]=c[k][i-1]*(k-i+1)/i;
for(int i=0;i<=k;i++)
c[k][i]/=temp;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
init();
memset(dp,0,sizeof(dp));
dp[0][0]=1.0;
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 tt=j+k-n;
for(int t=0;t<=k;t++)
dp[i+1][j+t-tt]+=dp[i][j]*c[k][t];
}
}
}
double ans=0.0;
for(int i=0;i<=n;i++)
ans+=i*dp[m][i];
printf("%.3f\n",ans);
}
}