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.
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.
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.
2 2
0.6666666666666666
4 4
0.4000000000000000
1 2
1.0000000000000000
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; }