数学期望题(概率+递推)。注意使用大整数。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Scanner;
/**
* 题意:一共有 n 种不同的优惠券,得到每种优惠券的概率相同。问期望多少次可以得到所有 n 种优惠券,以带分数形式输出。
* 数据范围: 1 <= n <= 33
*
* 分析:假设当前已经有 k 种优惠券,那么 p(获得新的优惠券) = (n-k)/n,所以需要步数的期望是 n/(n-k)。
* 求和得到步数的期望是 n/n+n/(n-1)+...+n/1 = n(1/n+1/(n-1)+...+1/1) = n(n!/1+n!/2+...+n!/n) / n!
*
* @author TinyDolphin
*
*/
public class Main {
/**
* 获得分母,即:N!
*/
public static BigInteger getDenominator(int N) {
BigInteger denominator = BigInteger.valueOf(1);
for (int i = 2; i <= N; i++) {
denominator = denominator.multiply(BigInteger.valueOf(i));
}
return denominator;
}
/**
* 得到分子,即:( N!/1+N!/2+N!/3+...N!/N ) * N
*/
public static BigInteger getMember(int N, BigInteger denominator) {
BigInteger member = denominator;
for (int i = 2; i <= N; i++) {
member = member.add(denominator.divide(BigInteger.valueOf(i)));
}
return member.multiply(BigInteger.valueOf(N));
}
public static void main(String[] args) {
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
int inputN;
BigInteger denominator; // 分母
BigInteger member; // 分子
BigInteger gcd; // 分子和分母的最大公约数
int resultInt; // 结果的整数部分
while (in.hasNext()) {
inputN = in.nextInt();
denominator = getDenominator(inputN);
member = getMember(inputN, denominator);
gcd = member.gcd(denominator);
// 用以上得到的分子和分母的最小公约数 gcd,简化分子和分母
denominator = denominator.divide(gcd);
member = member.divide(gcd);
// 得到最终的整数部分
resultInt = member.divide(denominator).intValue();
// 得到最终的分子
member = member.mod(denominator);
if (member.intValue() == 0) {
out.println(resultInt);
} else {
// 以下为分数的输出
// 输出分子前面的空格
int temp = resultInt;
while (temp > 0) {
out.print(" ");
temp /= 10;
}
// 输出空格+分子
out.println(" " + member);
// 输出整数部分+空格
out.print(resultInt + " ");
// 输出分子分母之间的 ----- ("-"的数量就是分母的位数)
BigInteger tempBint = denominator;
while (tempBint.compareTo(BigInteger.valueOf(0)) > 0) {
out.print("-");
tempBint = tempBint.divide(BigInteger.valueOf(10));
}
out.println();
// 输出分母前面的空格
temp = resultInt;
while (temp > 0) {
out.print(" ");
temp /= 10;
}
// 输出空格+分母
out.println(" " + denominator);
}
}
out.flush();
}
}