zoukankan      html  css  js  c++  java
  • HDU1133_50元跟100元去买票_catalan_大数运算

    题目大意: 很多人排队去买票,然后票价为50,但是每个人带的钱不一样,有的人带了50,有的人带了100,而那个票站一开始是没有钱的,这个买票的过程终结当票站没有钱,而有人拿100元去买票的时候。要求算出有多少种可能满足大家都可以买到票。 解题思路: 卡特兰数的百度百科上描述了这个过程,可以参考下: 下面的转自:http://hi.baidu.com/a363310925/blog/item/aced542d719b2b5d4fc22695.html hdu1133题的公式:(C(m+n, n)-C(m+n, m+1))*m!*n! 化简即(m+n)!*(m-n+1)/(m+1) m个人拿50,n个人拿100 , 所以如果 n>m,那么排序方法数为 0 这一点很容易想清楚

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

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

    最后化简为(m+n)!*(m-n+1)/(m+1);然后就是大数运算了。

    #include
    using namespace std;
    const int MAX = 100005;
    
    int len;
    
    void multip(int *ans_fa, int b)
    {
        int carry = 0;
        for(int j = 0; j < len; j++)
        {
            ans_fa[j] = ans_fa[j] * b + carry;
            carry = ans_fa[j] / 10;
            ans_fa[j] %= 10;
        }
        while(carry)
        {
            len++;
            ans_fa[len-1] = carry % 10;//少了模10
            carry /= 10;
        }
    }
    
    void division(int *ans_fa, int div)
    {
        int temp, r = 0;
        for(int i = len - 1; i >= 0; i--)
        {
            temp = ans_fa[i] + 10 * r;
            ans_fa[i] = temp / div;
            r = temp % div;
        }
        while(!ans_fa[len-1])
        {
            len--;
        }
    }
    
    void factor(int *ans_fa, int num)
    {
        for(int i = 1; i <= num; i++)
        {
            multip(ans_fa, i);
        }
    }
    
    void output(int *ans_fa, int cas_c)
    {
        printf("Test #%d:\n", cas_c);
        for(int i = len - 1; i >= 0; i--)
            printf("%d", ans_fa[i]);
        printf("\n");
    }
    
    int main(void)
    {
        int m, n, cas_c = 0;
        int ans_fa[MAX];
        while(scanf("%d%d", &m, &n), m || n)
        {
            if(n > m)
            {
                printf("Test #%d:\n", ++cas_c);
                printf("0\n");
                continue;
            }
            ans_fa[0] = 1;
            len = 1;
            factor(ans_fa, m + n);
            //output(ans_fa, cas_c);
            multip(ans_fa, m + 1 - n);
            //output(ans_fa, cas_c);
            division(ans_fa, m + 1);
    
            cas_c++;
            output(ans_fa, cas_c);
        }
    }
    
  • 相关阅读:
    算法竞赛入门经典习题2-3 韩信点兵
    ios入门之c语言篇——基本函数——5——素数判断
    ios入门之c语言篇——基本函数——4——数值交换函数
    144. Binary Tree Preorder Traversal
    143. Reorder List
    142. Linked List Cycle II
    139. Word Break
    138. Copy List with Random Pointer
    137. Single Number II
    135. Candy
  • 原文地址:https://www.cnblogs.com/cchun/p/2520228.html
Copyright © 2011-2022 走看看