题目大意:
就是现在一个袋子里装有C种颜色的巧克力每种各无数个, 现在从袋子当中每次拿出一颗巧克力放在桌上,如果桌上有2颗一样颜色的巧克力则吃掉他们, 问取N次之后桌子上正好有M颗巧克力的概率 (N, M <= 1000000, C <= 100)
大致思路:
这题很明显可以找到状态转移方程, 然后就是N的大小问题, 由于N很大但是题目要求的精度只有0.001所以可以减小N的范围来估算, 细节见代码注释
代码如下:
/*
* Author: Gatevin
* Created Time: 2014/12/24 14:41:45
* File Name: Sora_Kasugano.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
/*
* 如果用dp[i][j]表示拿出i颗巧克力后桌面上剩下j颗巧克力的概率
* 很明显有dp[i][j] = dp[i - 1][j - 1]*(C - (j - 1))/C + dp[i - 1][j + 1]*(j + 1)/C;
* 初始时dp[0][0] = 1;
* 考虑到内存限制需要使用滚动数组
* 另外如果M > min(C, N), 显然这个情况是不可能的概率为0
* 如果N - M不是奇数,这N - M颗巧克力不会全部消失, 不会剩下M颗, 此种情况概率为0
* 既便如此复杂度依旧是O(N*min(N, C)) 对于多组数组显然不可行
* 考虑到这是一条markov链, 当n达到一定数值的时候精度误差会小于1e-3并且趋于稳定
* 测试了下对于n > 500 分奇偶取500和501即可
* 分奇偶有个很明显的原因对于奇数N变成偶数N - M的奇偶性也会变, 很明显要保持N的奇偶性来保持可行性
*/
double dp[510][2];
int main()
{
int C, N, M;
while(scanf("%d", &C), C)
{
scanf("%d %d", &N, &M);
if(M > min(C, N) || ((N - M) & 1))
{
printf("0.000\n");
continue;
}
if(N > 500) N = (N & 1) + 500;
for(int i = 0; i <= N; i++) dp[i][0] = dp[i][1] = 0;
dp[0][0] = dp[0][1] = 1;
int now = 1;
for(int i = 1; i <= N; i++)
{
now ^= 1;
for(int j = 0; j <= min(C, N); j++)
if((i - j) & 1) dp[j][now] = 0;
else
{
dp[j][now] = 0;
if(j + 1 <= min(C, N))
dp[j][now] += dp[j + 1][now ^ 1]*(j + 1.0)/C;
if(j - 1 >= 0)
dp[j][now] += dp[j - 1][now ^ 1]*(C - j + 1.0)/C;
}
}
printf("%.3f\n", dp[M][now]);
}
return 0;
}