题目:HDU-1133 Buy the Ticket
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1133
题目:
3 0 3 1 3 3 0 0
Test #1: 6 Test #2: 18 Test #3: 180
题目分析,有n+m个人去买票,m个人拿50,n个人拿100,问有几种安排人排队的方法。明显是一个有关组合的问题,我们先判断一下特殊情况,只有在m>=n的情况下才可能安排排队,否则钱是找不开的,而且n=0时全是拿50的,那直接n的阶乘就好了。在一般情况下,可以列一个n*m的矩阵来表示答案,而且因为只要有几种排队方法确定以后直接乘以n的阶乘和m的阶乘就可以了,所以我们可以把n个人视为一样的,m个人视为一样的。那么就可以确定一般情况时排队方法有多少种。
则第m+n个人的排队方式可以看做多了第m+n个人,本来已经有了(m+n-1)个人,如果这个人拿的是50,那么就是在((m-1)+n)的基础上多了一个人,此时第m+n个人站在最后面(因为每个人都一样,所以实际上已经考虑了所有的情况),同样,如果这个人拿的是100,那么就是在(m+(n-1))的基础上多了一个人,因为人 都一样,所以又有(m,n-1)这种情况的种类,那么第m+n个人的排队类数就是(m,n-1)和(m-1,n)的和,(事实上如果最后来的那个人不站最后面那么就会出现重复的排队数,你可以试试用笔推一下)。那么递推式就出来了,我们就可以用打表的方法利用递推把m,n个人对应的排队数目用数组存储起来
嗯哼,这个做法当然不是我想的,我要是有这么聪明就好了=-=。唉,我这令人担忧的智商。
我们可以发现,对角线上的数字就是卡特兰数,也就是说如果m=n,那么排队数目就是卡特兰数 。
之后求阶乘的步骤就不用再说,排队的种类数乘以m的阶乘和n的阶乘就去掉了我们之前把拿同一种钞票的人视为一样的做法的影响了,那么我们得到的就是最终答案了。小提示,求m和n的阶乘的时候即使是0的阶乘也要注意返回一个1,否则当n=0时计算结果就会出现错误~~
啦啦啦,上代码~~
import java.util.*; import java.math.*; public class Main { public static void main(String[] args){ Scanner input=new Scanner(System.in); BigInteger a=new BigInteger("1"); BigInteger c=new BigInteger("0"); BigInteger ans[][]=new BigInteger[105][105]; for(int i=0;i<=100;i++) for(int j=0;j<=100;j++){ if(i<j) ans[i][j]=c; else if(j==0) ans[i][j]=a; else{ ans[i][j]=ans[i][j-1].add(ans[i-1][j]); } } int count=0; while(true){ int m=input.nextInt(),n=input.nextInt(); if(m==0 && n==0) break; BigInteger e=new BigInteger("1"); BigInteger f=new BigInteger("0"); for(int i=1;i<=m;i++){ f=f.add(a); e=e.multiply(f); } BigInteger g=new BigInteger("1"); BigInteger h=new BigInteger("0"); for(int i=1;i<=n;i++){ h=h.add(a); g=g.multiply(h); } BigInteger b=ans[m][n].multiply(e).multiply(g); System.out.println("Test #"+ ++count+":"); System.out.println(b); } } }好好学习,天天向上,加油~~~