阶乘的因子个数

求n!中有多少个质因子p

10!中质因子2的个数:

10!12345678910
10!中有因子21的数0101010101
10!中有因子22的数0001000100
10!中有因子23的数0000000100

因此10!中质因子2的个数有5+2+1=8个。
仔细思考,n!中有(n/p + n/p2 + …… )个这个质因子p,其中除法均为向下取整。
O(logn)

//计算n!中有多少个质因子p
int cal(int n,int p){
	int ans = 0;
	while(n){
		ans += n/p;
		n /= p;
	}
	return ans;
}
求n!中有多少个因子

  由上面可以得出,遍历一遍<=n的质数,依次求解该质因子个数c[i],最后 *(c[i]+1)即可

int pri[maxn],tot;	//maxn>n即可
bool v[maxn];
int c[maxn];
void primes()	//筛素数
{
    memset(v,true,sizeof(v));
    tot = 0;
    for(int i=2;i<maxn;i++){
        if(v[i]){
            pri[++tot] = i;
        }
        for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
            v[i*pri[j]] = 0;
            if(i%pri[j]==0) break;
        }
    }
}

void cal(int n)	
{
    int p,ans;
    for(int i=1;i<=tot;i++){
        p = pri[i];ans = 0;
        while(n/p){
            ans += n/p;
            p *= pri[i];
        }
        c[i] += ans;
    }
}

ll ans = 1;
for(int i=1;i<=tot;i++)
    ans *= (c[i]+1);
拓展: C(n,m)的因子个数:

  C(n,m) = n ! m ! ( n − m ) ! \frac{n!}{m!(n-m)!} m!(nm)!n!

方法一:

  暴力解决:依次求解n!每个质因子的个数a[i],m!每个质因子的个数b[i],(n-m)!每个质因子的个数c[i],*(a[i]-b[i]-c[i]+1);

int pri[maxn],tot;
bool v[maxn];
int c[maxn];
void primes()
{
    memset(v,true,sizeof(v));
    tot = 0;
    for(int i=2;i<maxn;i++){
        if(v[i]){
            pri[++tot] = i;
        }
        for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
            v[i*pri[j]] = 0;
            if(i%pri[j]==0) break;
        }
    }
}
void cal(int n,int d)
{
    int p,ans;
    for(int i=1;i<=tot;i++){
        p = pri[i];ans = 0;
        while(n/p){
            ans += n/p;
            p *= pri[i];
        }
        c[i] += d*ans;
    }
}
	cal(n,1);	//n!每个质因子的个数
	cal(m,-1);	//m!每个质因子的个数
	cal(n-m,-1);	//(n-m)!每个质因子的个数

	ll ans = 1;
	for(int i=1;i<=tot;i++)
    	ans *= (c[i]+1);	//因子个数
打表

  j!中每个素因子的个数,公式如下:num[j][i] = j/pri[i] + num[j/pri[i]][i];

int pri[maxn],tot;
bool v[maxn];
int num[maxn][maxn];
ll c[maxn][maxn];
void solve()
{
    memset(v,true,sizeof(v));
    tot = 0;
    for(int i=2;i<maxn;i++){
        if(v[i]){
            pri[++tot] = i;
        }
        for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
            v[i*pri[j]] = 0;
            if(i%pri[j]==0) break;
        }
    }

    for(int i=1;i<=tot;i++){
        for(int j=1;j<maxn;j++){
            num[j][i] = j/pri[i] + num[j/pri[i]][i];
        }
    }
    for(int i=1;i<maxn;i++){
        for(int j=1;j<i;j++){
            c[i][j] = 1;
            for(int k=1;k<=tot;k++){
                int d = num[i][k] - num[j][k] - num[i-j][k];
                c[i][j] *= (d+1);
            }
        }
    }
}
	if(m==0||n==m)  
		printf("1\n");
	else    
		printf("%lld\n",c[n][m]);

例题:POJ 2992 Divisors http://poj.org/problem?id=2992
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 263 - 1.
Sample Input

5 1
6 3
10 4
Sample Output

2
6
16

题意

  求解C(n,m)的因子个数。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn = 440;
const int inf = 0x3f3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f;
const ll mod =  1000000007;
int pri[maxn],tot;
bool v[maxn];
int c[maxn];
void primes()
{
    memset(v,true,sizeof(v));
    tot = 0;
    for(int i=2;i<maxn;i++){
        if(v[i]){
            pri[++tot] = i;
        }
        for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
            v[i*pri[j]] = 0;
            if(i%pri[j]==0) break;
        }
    }
}
void cal(int n,int d)
{
    int p,ans;
    for(int i=1;i<=tot;i++){
        p = pri[i];ans = 0;
        while(n/p){
            ans += n/p;
            p *= pri[i];
        }
        c[i] += d*ans;
    }
}
int main(void)
{
    int k,n;
    primes();
    while(~scanf("%d%d",&n,&k)){
        memset(c,0,sizeof(c));
        cal(n,1);cal(k,-1);
        cal(n-k,-1);

        ll ans = 1;
        for(int i=1;i<=tot;i++)
            ans *= (c[i]+1);
        printf("%lld\n",ans);
    }
    return 0;
}
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn = 440;
const int inf = 0x3f3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f;
const ll mod =  1000000007;
int pri[maxn],tot;
bool v[maxn];
int num[maxn][maxn];
ll c[maxn][maxn];
void solve()
{
    memset(v,true,sizeof(v));
    tot = 0;
    for(int i=2;i<maxn;i++){
        if(v[i]){
            pri[++tot] = i;
        }
        for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
            v[i*pri[j]] = 0;
            if(i%pri[j]==0) break;
        }
    }

    for(int i=1;i<=tot;i++){
        for(int j=1;j<maxn;j++){
            num[j][i] = j/pri[i] + num[j/pri[i]][i];
        }
    }
    for(int i=1;i<maxn;i++){
        for(int j=1;j<i;j++){
            c[i][j] = 1;
            for(int k=1;k<=tot;k++){
                int d = num[i][k] - num[j][k] - num[i-j][k];
                c[i][j] *= (d+1);
            }
        }
    }
}
int main(void)
{
    int k,n;
    solve();
    while(~scanf("%d%d",&n,&k)){
        if(k==0||n==k)  printf("1\n");
        else    printf("%lld\n",c[n][k]);
    }
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逃夭丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值