POJ 2992
[题目大意]
求组合C(n,k)的全部因子个数。
[核心要点](数论基本知识)
第一:C(n,k) = n! / k! / (n - k )!
无需证明,可自己推导
第二:对于所有正整数n,都可按素因子分解为n=p1^a1*p2^a2*....*pk^ak(其中pi均为素数),那么n的约数的个数为(a1+1)(a2+1)...(ak+1);
例如:12 = 2 ^ 2 * 3 ; 12 的约数个数有(2 + 1) * (1 + 1) = 6个(1 ,2 ,3 ,4 ,6 ,12);
(不会证明qaq)
第三:对于一个素数p,n!中按素因子分解,p的幂为 n/p+n/p^2+n/p^3...,其中/为整除;
即,ai = n/pi+n/pi^2+n/pi^3...
例如:4!(24 ) = 2 ^ 3 * 3 ;其中,2的幂次为 4 / 2 + 4 / 2 ^ 2 = 3 ; 3的幂次为 4 / 3 = 1;
(不会证明qaq)
第四:基于以上第三点,推导如下:
设n!中素因子p的个数为:a=n / p+n / (p^2)+...+n / (p^k)+...
那么(n/p)!中素因子p的个数为:b = n/(p^2)+...+n/(p^k)+...
很显然a=b+n/p,因此可以利用上述递推公式预处理出所有的j!中每个素因子的个数。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
const int N = 500;
bool Prime[N];
int jie[N][90];
ll zu[N][N];
int Primer[N],num;
//在Prime[500]打素数表
void GetPrime()
{
for(int i = 2; i <= 431; ++i)
Prime[i] = true;
for(int i = 2; i <= 431; ++i)
{
if(Prime[i])
{
for(int j = i+i; j <= 431; j+=i)
Prime[j] = false;
}
}
num = 0;
for(int i = 0; i <= 431; ++i)
if(Prime[i]) Primer[num++] = i;
}
void solve()
{
//阶乘分解为 素因子相乘的形式jie[j][i]表示 j! 第i个素数的幂为多少
for(int i = 0;i < num; ++i)
for(int j = 2; j <= 431; ++j)
jie[j][i] = j/Primer[i] + jie[j/Primer[i]][i];
for(int i = 2; i <= 431; ++i) //计算因子个数
{
for(int j = 1; j < i; ++j)
{
zu[i][j] = 1;
for(int k = 0; k < num && jie[i][k]; ++k)
{
int side = jie[i][k] - jie[j][k] - jie[i-j][k]; //计算C(i,j)中第i个素数的幂为多少
if(side)
zu[i][j] *= (side+1); //求因子个数
}
}
}
}
int main()
{
GetPrime();
solve();
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(m==0 || m==n)
printf("1\n");
else
printf("%I64d\n",zu[n][m]);
}
return 0;
}
[Reference]
https://blog.csdn.net/lianai911/article/details/44598155#commentBox https://blog.csdn.net/u011008379/article/details/20408063
数论部分强烈推荐