Divisors
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 10847 | Accepted: 3214 |
Description
Your task in this problem is to determine the number of divisors of
Cnk. Just for fun -- or do you need any special reason for such a useful computation?
Input
The input consists of several instances. Each instance consists of a single line containing two integers n and k (0 ≤ k ≤ n ≤ 431), separated by a single space.
Output
For each instance, output a line containing exactly one integer -- the number of distinct divisors of
Cnk. For the input instances, this number does not exceed 2
63 - 1.
Sample Input
5 1 6 3 10 4
Sample Output
2 6 16
题目大意:
求Cnk的素数因子的个数,由于n和k偏大,直接计算后算素数因子的个数显然不可能,所以我们可以利用一些数论技巧,我们需要知道几条定理:
(1) :n!的素因子分解中的素数p的幂为:
[n/p] + [n/p^2] + [n/p^3] ......+[n/p^n],(n >= p ^ n)
(2):若n的标准素因子分解表达式为n = p1 ^ a1 + p2 ^ a2 + p3 ^ a3 + ......pn^an,n的正因子的个数为ans = (a1 + 1) * (a2 + 1) * (a3 + 1) ......*(an + 1).
解题思路:
由于题目n和k给的范围是431,所以打表431以内的素数,然后依次从小到大枚举素数,计算幂值,当枚举完所有的素数幂值后,套用公式二得解。然后题目给的是Cnk,所以必须化成阶乘的形式。Cnk = n! / (n-k)!k!,计算的时候只要上面减掉下面两个就可以了。
AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1000;
bool isprime[maxn];
int prime[maxn];
int nprime;
int cnt[maxn];
void doprime() //筛法
{
long long i,j;
nprime = 0;
memset(isprime,true,sizeof(isprime));
isprime[1] = 0;
for(i=2;i<=450;i++)
{
if(isprime[i])
{
prime[++nprime] = i;
//cout<<nprime<<" "<<i<<endl;
for(j = i*i;j<=450;j+=i)
{
isprime[j] = false;
}
}
}
}
int calc(int num,int p) //递归计算素数的幂
{
if(num < p) //num / p = 0;
{
return 0;
}
if(p != 0)
return num / p + calc(num/p,p);
}
long long com(int num1,int num2)
{
long long ans = 1;
int i;
//cout<<nprime<<endl;
for(i=0;i<=nprime;i++) //枚举质因数求幂
{
cnt[i] = calc(num1,prime[i]); //计算因子的幂
cnt[i] -= calc(num1-num2,prime[i]);
cnt[i] -= calc(num2,prime[i]);
ans *= (cnt[i] + 1); //素数的幂+1连乘等于个数
//cout<<ans<<endl;
}
return ans;
}
int main()
{
int m,n;
doprime();
while(scanf("%d%d",&m,&n) != EOF)
{
long long result = com(m,n);
cout<<result<<endl;
}
return 0;
}