C. Magic Trick

time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Alex enjoys performing magic tricks. He has a trick that requires a deck of n cards. He has m identical decks of n different cards each, which have been mixed together. When Alex wishes to perform the trick, he grabs n cards at random and performs the trick with those. The resulting deck looks like a normal deck, but may have duplicates of some cards.

The trick itself is performed as follows: first Alex allows you to choose a random card from the deck. You memorize the card and put it back in the deck. Then Alex shuffles the deck, and pulls out a card. If the card matches the one you memorized, the trick is successful.

You don't think Alex is a very good magician, and that he just pulls a card randomly from the deck. Determine the probability of the trick being successful if this is the case.

Input

First line of the input consists of two integers n and m (1 ≤ n, m ≤ 1000), separated by space — number of cards in each deck, and number of decks.

Output

On the only line of the output print one floating point number – probability of Alex successfully performing the trick. Relative or absolute error of your answer should not be higher than 10 - 6.

Sample test(s)
input
2 2
output
0.6666666666666666
input
4 4
output
0.4000000000000000
input
1 2
output
1.0000000000000000
Note

In the first sample, with probability  Alex will perform the trick with two cards with the same value from two different decks. In this case the trick is guaranteed to succeed.

With the remaining  probability he took two different cards, and the probability of pulling off the trick is .

The resulting probability is 

题解前屁话:这题目真的很好...

题目大意是一个魔术师有m叠牌,每叠n张他每次都抽取n张出来。观众从中选一张,他也随即抽一张,问他成功的概率。

好,这题如果你按照正常的数学思路去分析,那你就死定了。

从程序角度分析,我们容易想到去枚举n张牌中相同的牌有几张(i),然后计算抽到这张牌的概率。

我开始想用两层for,一层枚举牌面数字,一层枚举该种牌数量,可是写出来后发现没必要。(这里可以自己试试看)

于是结合数学知识(注意是结合!!)我们可以写出通式:( Com(m,j)*Com((n-1)*m,n-j)*j^2 )/ (Com(n*m,n)*n^2 )

但是别忘了,我们只有一层for循环,结果最后可是要*n的。

这样看似问题解决了,其实不然,如果你真的这样写肯定不是在第5点TLE就是WA(其实是数太大溢出了)。因为数太大的缘故,所以我们对所有的计算过程取对数,这样原来的乘法变为加法,数也更小了。(这一点是我参考了别人的程序.....)

事实证明,这样修改过的程序已经可以再误差范围内AC了~~

现在贴上代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
double ans=0,u=0,t=0;

double Com(int n,int k) {
double t=0;
for (int i=1;i<=k;++i)
    t+=(log(n-i+1)-log(i));
return t;
}

int main() {
double n=0,m=0;
cin >> n >> m;
u=Com(n*m,n);
for (int j=1;j<=min(n,m);++j) {
    t=(Com(m,j)+log(j*j)+Com((n-1)*m,n-j))-(Com(n*m,n)+log(n));
    ans+=exp(t);
    }
printf("%.16f\n", ans);
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值