U: A Easy Problem
Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 229 Solved: 8Description
This is a classical problem. Your job is to calculate the combination formula
C
(
n
,
m
)
, and
C
(
n
,
m
)
fit a 64-bit unsigned integer.(注意答案的范围)
Input
The first line of input there is one integer
T
(
T
≤
100), giving the number of test cases in the input. Each test case contains a line with two integer n and m(0
≤
m
≤
n
<2
64
).
Output
For each case, output
the answer
C
(
n
,
m
) corresponding to the input.
Sample Input
1 4 2
Sample Output
6
题意很简单就是求组合数。m,n会很大。
无符号的64位数,范围在0~1.84*10^19. 这也是题目上说的答案范围。
当m>n/2时,m=n-m。这时可知m不会很大,否则会超过范围。m大概小于34
然后就用组合数公式计算:
公式分子有m相,分母也有m相。直接算会爆
一开始的想法是:把分子保存在数组temp中。外层遍历分母的m-1相i= 2,3,4~m,内层遍历分子每一项temp[j],判断有没有分子相可以除尽i,若有,则约掉。即temp[j] = temp[j] / i
因为结果是整数,这时误以为分母的每一项都有分子可以除尽它,所以计算temp数组的积。但不对,可能分母有的相无法约掉,需要
两个,甚至更多的分子相的积才能约掉。
其实用gcd求一下最大公约数就行了。
遍历分母的m-1相i= 2,3,4~m,内层遍历分子每一项temp[j],计算gcd(i, temp[j])。然后约掉就行了。因为最后是整数,所以最后分母相一定都被约掉了。结果就是temp数组的积
#include <cstdio>
typedef unsigned long long ll;
ll compute(ll a, ll b);
ll temp[200];
int m_temp[200];
ll gcd(ll a, int b)
{
if (b == 0)
{
return a;
}
return gcd(b, a % b);
}
int main()
{
int T;
ll m, n;
scanf("%d", &T);
while (T--)
{
scanf("%llu %llu", &n, &m);
ll ans = compute(n, m);
printf("%llu\n", ans);
}
return 0;
}
ll compute(ll a, ll b)
{
if (b > a / 2)
{
b = a - b;
}
if (b == 0)
{
return 1;
}
ll ans = 1;
for (int i = 0; i < b; i++)
{
temp[i] = a - i;
m_temp[i] = i + 1;
}
for (int i = 0; i < b; i++)
{
for (int j = 0; j < b; j++)
{
int g = gcd(temp[j], m_temp[i]);
temp[j] = temp[j] / g;
m_temp[i] = m_temp[i] / g;
}
}
for (int i = 0; i < b; i++)
{
ans = ans * temp[i];
}
return ans;
}