题目意思很明确, 就是求C(k , n) (0 ≤ k ≤ n ≤ 431)的因子个数,保证答案不会超long long。
很容易想到用唯一分解定理来求解 , 想办法将C(k , n)变为
p1^e1 * p2^e2 * ... * pn^en
那么很容易得出它的因子个数为
(1 + e1) * (1 + e2) * ... * (1 + en)
由于
C(k , n) = n! / (k! * (n - k)!)
因此, 这个题的关键点在于如何快速求出n! , k! , (n-k)!的素因子以及相应的幂,然后把对应因子个数相减即可。
快速求N!的素因子以及相应的幂
- 对于不大于N的素数p,因为1 ~ N 中存在N/p个数能够被p整除。所以N!中至少存在N/p个p。
- 提取出来上述能够被p整除的数, 然后再除以p, 就得到的 1 , 2 , … , N/pi 的序列。同样的方法求(N/p)!中含有多少个p。
- 一直进行上述操作, 便能得到N!中素因子p的幂。
即 N!关于素数p的因子数
factor(N! , p) = N/p + N/(p^2) + N/(p^3) + ... + N/(p^m)
因此 , 只需要对每一个不大于N的素数进行以上操作, 便能求出N!的素因子以及相应的幂。
代码
#include <iostream>
#include <cstdio>
using namespace std;
#define MAXN 431
typedef long long ll;
int prim[500] , ispri[500] , cnt;
//小于N的所有素数
void get_prim(int N)
{
cnt = 0;
for(int i = 2; i < N; i++) if(!ispri[i]) {
prim[cnt++] = i;
for(int j = i * i; j < N; j += i) ispri[j] = 1;
}
}
//p[i]存储i!对应的素因子的幂
int p[MAXN+1][MAXN+1] = {{0} , {0}};
void Init()
{
get_prim(500);
//预处理出来所有数的阶乘对应的素因子的幂
for(int k = 2; k <= MAXN; k++)
{
//factor(N! , p) = N/p + N/(p^2) + N/(p^3) + ... + N/(p^m)
for(int i = 0; prim[i] <= k; i++) {
int tmp = prim[i];
while(k / tmp) {
p[k][prim[i]] += k / tmp;
tmp *= prim[i];
}
}
}
}
int main()
{
Init();
int n , k;
while(scanf("%d%d" , &n , &k) != EOF)
{
ll ans = 1;
int cur[MAXN+1] = {0};
for(int i = 2; i <= MAXN; i++) cur[i] = p[n][i] - p[n-k][i] - p[k][i];
for(int i = 2; i <= MAXN; i++) if(cur[i]) ans *= 1 + cur[i];
cout << ans << endl;
}
return 0;
}