Buy the Ticket&&http://acm.hdu.edu.cn/showproblem.php?pid=1133

64 篇文章 0 订阅

卡特兰数的变种,,,

这里可以把100元看做出栈,50元看做进栈,判断合法的顺序,,

 

题意:M+N个人排队买票,票的单价是50¥,每个人只能买一张。 M个人拿50的去买,N个人拿100的去买,然后悲剧的是售票处开始的时候没有钱,所以如果拿100块买票人前面的拿50块买票的人小于或者等于用100块买票的人,这种排队方式就不合法,也就是不能顺利全部都买到票(因为没零钱找了)!

卡特兰数的应用

该题的公式(C(m+n, n)-C(m+n, m+1))*m!*n! 化简即(m+n)!*(m-n+1)/(m+1)

m个人拿50n个人拿100 所以如果 n>m,那么排序方法数为 0 这一点很容易想清楚

现在我们假设50的人用 ‘0’表示,100的人用 1 表示。

如果有这么一个序列 0101101001001111..........
当第K个位置出现1的个数多余0的个数时就是一个不合法序列了
假设m=4 n=3的一个序列是:0110100 显然,它不合法,现在我们把它稍微变化一下:
把第二个1(这个1前面的都是合法的)后面的所有位0变成11变成0
就得到 0111011 这个序列1的数量多于0的数量,显然不合法,但现在的关键不是看这个序列是不是合法的
关键是:它和我们的不合法序列 0110100 成一一对应的关系
也就是说任意一个不合法序列(m0n1)都可以由另外一个序列(n-10m+11)得到
另外我们知道,一个序列要么是合法的,要么是不合法的
所以,合法序列数量 = 序列总数量 - 不合法序列的总量
序列总数可以这样计算m+n 个位置中,选择 n 个位置出来填上 1所以是 C(m+n, n)
不合法序列的数量就是: m+n 个位置中,选择 m+1 个位置出来填上 1 所以是 C(m+n, m+1)
然后每个人都是不一样的,所以需要全排列 m! * n!

题目还涉及到了大数乘小数,还有大数除小数

AC代码:

import java.util.*;
import java.math.BigInteger;
public class Main {

	/**
	 * @param args
	 */
	
	private static BigInteger f(int n)
	{
		BigInteger sum=BigInteger.ONE;
		for(int i=2;i<=n;++i)
			sum=sum.multiply(BigInteger.valueOf(i));
		return sum ;
		
	}
	
	public static void main(String[] args) {
		// TODO 自动生成方法存根
		Scanner cin=new Scanner(System.in);
		
		int tot=0;
		while(cin.hasNext())
		{
			int n=cin.nextInt();
			int m=cin.nextInt();
			tot++;
			if(n==0&&m==0) break; 
			if(n<m)
				{
				System.out.println("Test #"+tot+":");
				System.out.println(0);
				continue;
				}
			int ans=n+m;
			BigInteger res=f(ans);
			res=res.multiply(BigInteger.valueOf(n-m+1)).divide(BigInteger.valueOf(n+1));
			System.out.println("Test #"+tot+":");
			System.out.println(res);
			}
	}

}


 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值