A - 蝙蝠(组合数问题)

74 阅读3分钟
这一切都要从一只蝙蝠说起。 我叫灰灰,是一只蝙蝠。我和我的家族住在又深又暗的山洞里。 一天,我去找我的好朋友——穿山甲球球玩。到了他家,只见球球的爸爸妈妈边流泪边默默地收拾东西。我一问才知道,球球被一种叫人类的动物抓走了,我只好伤心地回家了。 第二天,我和兄弟姐妹们在山洞外玩儿。忽然我听到了一些奇怪的声音。哥哥急忙对我们说:“又是那些人类!我们快躲起来。”于是我们赶快回家找爸爸妈妈,可是已经来不及了。为了保护我们,爸爸妈妈也被人类抓住了。 我难过地问哥哥:“人类为什么要抓走我们的爸爸妈妈?” 哥哥伤心地说:“他们很快就会被人类吃掉了。” 我不明白为什么,记得爸爸妈妈告诉我,以前人们都把我们当成是吉祥的象征。可现在,他们为什么还要吃我们呢?我很生气,我恨人类! 后来,我听说那些我们亲人的人类,都得了一种叫做“新型冠状病毒”的肺炎。好的,故事到此结束。开学了,由于疫情原因,同学们只能在家上网课,而老师在上课的时候为了确认所有的学生都有在听课,所以每节课都要点名。但是由于时间限制,每次老师只会点一部分同学,请问老师一共会有多少种不同的点名方式呢?
Input
数据的第一行包括一个正整数T,接下来有T组数据,每组数据占一行。
每组数据包含两个整数N(全班的人数,1<=N<=30),M(老师点名的人数0<=M<=30)
Output
每组数据输出一个整数,每个输出占一行
Sample Input
5
3 2
5 3
4 4
3 6
8 0
Sample Output
3
10
1
0
1
long long cnm(int n, int m)
{
    long long sum = 1;
    int k = 1;
    if (m > n / 2)
        m = n - m;
    for (int i = n - m + 1; i <= n; i++)
    {
        sum *= (long long)i;
        while (k <= m && sum % k == 0)
        {
            sum /= (long long)k;
            k++;
        }
    }
    return sum;
}
#include<stdio.h>
int main()
{
	long long t, sum, j, total, choose;
	scanf("%lld", &t);
	while (t--)
	{
		sum = 1;
		scanf("%lld %lld", &total, &choose);
		if (total >= choose)
		{

			printf("%lld\n",cnm(total,choose));

		}
		else
		{
			printf("0\n");
		}



	}


	return 0;
}

 上面的代码是后来通过优化才通过这道题的

下面给出我一开始写的代码

int fat(int n)
{
	int i;
	int sum=1;
	for(i=1;i<=n;i++)
	{
		sum*=i;
	}
	return sum;
	
}

#include<stdio.h>
int main()
{
	int t,sum,j,total,choose;
	scanf("%d",&t);
	while(t--)
	{
		sum=1;
		scanf("%d %d",&total,&choose);
		if(total>=choose)
		{
			for(j=total;j>total-choose;j--)
			{
				sum*=j;
			}
			printf("%d\n",sum/fat(choose));
			
		}
		else
		{
			printf("0\n");
		}
		
		
		
	}
	
	
	return 0;
}

如果你使用这个代码去测试sample input的话

你会发现都是正常输出

然而你并没有办法通过这道题

为什么呢!!!

你试试输入30 15

你会发现输出的结果根本不是我们想要的

原因就是溢出了

我们必须立刻优化!!!

首先对于像30 29 这样的输入都无法正常输出

我们可以利用Cnm=Cn(n-m)这个公式

所以我加了一个if(m>n/2)语句

然后就是对于求15! 都会溢出我们不妨不要一次性求出15!而是一个一个去除

这样就没问题了

这道题真是花了我不少时间