hdu 2519 新生晚会 (DP)

点击打开链接

ps:

c(n,m) = n!/(m!*(n-m)!)
如果n和m比较大时 可能会导致中间超过数据范围,不过我们可以直接用递推也就是
c(n,m) = c(n-1,m)+c(n-1,m-1)
不过下面我们要用另外一种方法来计算这个组合
把分子和分母约掉之后就变成了
(n*(n-1)*……*(n-m+1))/m!
这样上面和下面都是m个元素,我们可能会想到乘1个除1个,这样来避免越界,可是这样会刚好整除吗?不会出现小数使得最后的答案变错吗?其实只要我们按照一定的顺序来乘和除的话,是不会产生小数的,也就是说会一直整除的.

首先我们把上面那个分数写成这样的
(n*(n-1)*……*(n-m+1))/(m*(m-1)*……*1)
这样的话就相当于n–>m  (n-1)—>(m-1) …… (n-m+1)—>1
下面先给出主要程序吧
f = 1;//最后答案
for(i = 1;i <= m;i++)
  f = f*(i+(n-m))/i;
现在主要的是要说明每次乘以(i+(n-m))然后再除以i不会产生小数,我是这么想的,说先i是1,肯定不会有小数,然后i=2,但是分母已经乘过两个数了,肯定有一个奇数,一个偶数,也不会产生小数,同理3的时候也不会,但是4的时候可能会这样想,前面某个数k整除4,那已经别2除掉了一个2,这样会不会产生小数呢?结果是不会的,因为4个相当于2个2,或者1个4,我们可以把除2的那个选择到这4个当中不能出4的那一个数上,这样的话,就剩下了一个能整除4的了,然后其他的就和这里一样了。

#include"stdio.h"
int main()
{
    int t,n,m,i;
    double sum;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        if(n<m)
        { printf("0\n");
		continue;
        }
        sum=1;
        for(i=1;i<=m;i++)
            sum*=(n+1-i)/(double)i;
        printf("%.0f\n",sum);
    }
    return 0;
}


posted on 2012-10-14 17:39  Slege  阅读(74)  评论(0编辑  收藏  举报

导航