题目:http://poj.org/problem?id=2992
题意:求解出组合数C(n,k)的约数个数
储备知识:利用分解质因数求因子个数
如果 n = p1^a1*p2^a2...pk^ak;
那么因子个数为 (a1+1)*(a2+1)*...*(ak+1)
第一种思路:
将组合数按照分式形式把每个数进行分解,然后上下约分,最后求解。,但是死活超时。。。。
超时代码:
#include<cstring>
#include<cstdio>
using namespace std;
long long a[500],b[500];
int f[500];
int fi=0;
void fenjie1(int x){
int i=1;
while(x!=1){
while (x%f[i]==0) {
x=x/f[i];
a[f[i]]++;
}
i++;
}
}
void fenjie2(int x){
int i=1;
while(x!=1){
while (x%f[i]==0) {
x=x/f[i];
b[f[i]]++;
}
i++;
}
}
int main(){
for (int i=2; i<=500; i++){
bool b=true;
for (int j=2; j<i; j++)
if (i%j==0) { b=false; break; }
if (b) {
fi++;
f[fi]=i;
}
}
int n,k;
while(scanf("%d%d",&n,&k) == 2){
long long ans=1;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for (int i=n; i>n-k; i--) fenjie1(i);
for (int i=1; i<=k; i++) fenjie2(i);
for (int i=1; i<=n; i++)
a[i]=a[i]-b[i];
for (int i=1; i<=n; i++)
if (a[i]!=0) ans=ans*(a[i]+1);
printf("%ld\n",ans);
}
}
虽然这个题目这样做是超时的,但是我们的做法没有问题,问题是题目的数据组数很多。
那这样就意味着我们会分解很多很多相同的数,每次碰到都要分解,尽管之前分解过很多次了。
克服超时————记忆化一下或者提前预处理一下
先把所有能用到的数都给分解一遍 存起来,后面需要用的话直接用,就可以AC了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
bool Prime[500];
int jie[500][90];
__int64 zu[500][500];
int Primer[500],num;
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()
{
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;
}