参考题目:POJ - 2992
思路:打表(n!的质因数指数大小的表)
- 首先素数筛,把素数筛出来。
- 然后把每个阶乘的的质因子的指数存下来。使用累加,从1一直到431,可以把
1! ~ 431!
的表全部打出来。原理:num[i][primes[j]] = num[i - 1][primes[j]] + count1
,就是将上一个数字的指数累加到当前数上。 - 组合数公式: C n k = n ! / ( ( n − k ) ! ∗ k ! ) C^k_n = n! / ((n - k)! * k!) Cnk=n!/((n−k)!∗k!) 可以根据上一步打出来的阶乘数的质因子指数表,循环质数个数次得到答案
运行时间:
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 450;
int primes[N];
bool st[N];
int cnt;
int num[N][N];
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
// 线性筛
for (int i = 2; i <= 431; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] <= 431 / i; j ++ )
{
st[i * primes[j]] = true;
if (i % primes[j] == 0) break;
}
}
// 打质因数指数表
for (int i = 1; i <= 431; i ++ )
{
int num1 = i;
for (int j = 0; j < cnt; j ++ )
{
int count1 = 0;
while (num1 % primes[j] == 0)
{
count1 ++ ;
num1 /= primes[j];
}
num[i][primes[j]] = num[i - 1][primes[j]] + count1;
}
}
int n, k;
while (cin >> n >> k)
{
LL sum = 1;
for (int i = 0; i < cnt; i ++ )
{
LL up, down;
up = num[n][primes[i]] - num[n - k][primes[i]];
down = num[k][primes[i]];
sum *= (up - down + 1);
}
cout << sum << endl;
}
return 0;
}