HDU 1133 Buy the Ticket

HDU 1133 Buy the Ticket

题意:
有m个人只拿着50元的现金,有n个人只拿着100元的现金,票价50元。问有几种排队的方式,可以让售货员不用准备零钱就可以卖出所有的票。
思路:
我们可以把这道题的人分成两类,一种拿着50元的标记成0,另一种拿着100元的标记成1。
那么我们就可以得到一个长度为(n + m) 的01序列。
例如:0101
考虑这么一种情况
0110100,这是一个不合法的序列。因为从左向右看,在第3位的时候1的个数比0的个数多。
如果我们找到一个1使它前面的序列都合法,之后,在这个1的后面的所有0和1互换,那么我就得到了一个不合法的另一个序列011 1011
标记成粗体的是变过的01串。我们就可以利用这种转换,使所有不合法的串一一对应起来,因为转换过得串一定是不合法的(1的总数比0的总数多)。
那在求合法的情况时,就可以利用这种不合法(1的总数比0的总数多)的情况的个数来与总情况相减就可以了
(m为0的个数,n为1的个数。)
而这种不合法的情况数一共有C(n + m, m - 1)种。
这是怎么来的呢,我们可以进行下面的推导,因为找到的这个1前面的串是合法的,那么前面1的个数和0的个数相等设为x.
后面需要转换的:
0的个数为:m - x
1的个数为:n - x - 1(因为省去了找到的这个1)
经过转换的:
0的个数为:n - x - 1
1的个数为:m - x
转换后总共的:
0的个数为:n - x -1 + x = n - 1
1的个数为:m - x + x + 1 = m + 1
而合法的情况为C(n + m, n)(从n + m长度的串里面填n个1)
最后的总公式为:

[C(n + m, n) - C(n + m, m + 1)] * m! * n!//因为每个人都不同,所以需要乘上阶层数

化简得:

m + n)! * (m + 1 - n) / (m + 1

并且不要忘了另一种情况n > m,结果是0.
由于n + m的范围已经到了200,所以为了图方便,用了java的大数。
Code:

import java.math.BigInteger;
import java.util.Scanner;

public class Main
{
    public static void main(String args[])
    {
        Scanner cin = new Scanner(System.in);
        int T = 0;
        while(cin.hasNext())
        {
            int m = cin.nextInt();
            int n = cin.nextInt();
            if(m == 0 && n == 0)
            {
                break;
            }
            System.out.printf("Test #%d:%n", ++T);//如果要用printf,一定要写%n,因为杭电的windows平台%n才代表换行,\n不算。。。
            System.out.println("Test #" + (++T) + ":");
            if(n > m)
            {
                System.out.println(0);
                continue;
            }
            BigInteger ans = bv(1);
            for(int i = 1; i <= n + m; ++i)
            {
                ans = ans.multiply(bv(i));
            }
            ans = ans.multiply(bv(m + 1 - n)).divide(bv(m + 1));
            System.out.println(ans);
        }
    }

    public static BigInteger bv(int n)
    {
        return BigInteger.valueOf(n);
    }
}

你可能感兴趣的:(数学,HDU-1133)