原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1133
n:50元个数
m:100元个数
一看到这个题目我就顺着思路写了,先找出不同种排法再*n!*m!用BigInteger保存结果,最后超时。在捣鼓了很久之后在网上看到了首次接触的Catalan数,通过递推就很容易得到答案。
Cataland的一些详细介绍:http://daybreakcx.is-programmer.com/posts/17315.html
这里有一个很有意思的解法:
合法的序列 = 总序列 - 不合法的序列。总的序列是:C(m+n, n),而不合法的序列,假设最早买不到票的人为k,那么他必然是手持100元而且售票口没有钱,出现这种情况有两种可能,一种是他是第一个买票的;第二种是在他前面即买票的手持50和100元的人数相同。
即假设设手持50的为0,手持100的为1,让他们排成一排,则不合法的序列中必然能找得到第一个买不到票的人k,例如:01 1 01010,k = 2。这时候,将0-k的1置换成0,将0置换成1,就会出现序列中出现0的个数为n+1,1的个数为m-1,上面的通过置换后变成:10001010。也就是说,不合法的序列的个数为:C(m+n, n+1)。
所以得到公式:
Total = (C(m+n, n)-C(m+n, n+1))*m!*n!,化简得:(m+n)! * (n-m+1)/(n+1)
package com.HDU;
import java.math.BigInteger;
import java.util.Scanner;
public class Ticket2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n,m;
int count = 1;
while(in.hasNext()) {
n = in.nextInt();
m = in.nextInt();
if(n==0 && m==0)
break;
BigInteger ans = BigInteger.ONE;
if(n<m) ans = BigInteger.ZERO;
//(m+n)!
for(int i = 1;i<=n+m;i++)
ans=ans.multiply(BigInteger.valueOf(i));
int mpl = n-m+1;
int dvd = n+1;
ans = ans.multiply(BigInteger.valueOf(mpl));
ans = ans.divide(BigInteger.valueOf(dvd));
System.out.println("Test #"+count+":");
System.out.println(ans);
}
}
}