POJ2992 Divisors【因子个数】
         
                原创
        
    
    
                
             ©著作权归作者所有:来自51CTO博客作者ITCharge的原创作品,请联系作者获取转载授权,否则将追究法律责任        
            
                    
                
题目链接:
http://poj.org/problem?id=2992
题目大意:
求解出组合数C(n,k)的约数个数。
思路:
数据中的n和k值都比较大,直接求解显然不可以。求约数个数,要先进行素因子分解。
C(n,k) = n!/(k!*(n-k)!)。n范围小于等于431,可以先筛选出431以内的素数,用数组Primer[]来存储素数。
对每个阶乘进行素因子分解,用数组jie[i][j]来表示阶乘i进行分解式第j个素数的幂。然后求组合数的素因子
分解,利用公式得到因子个数。
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()
{
    //阶乘分解为 素因子相乘的形式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;
}