POJ2992:Divisors(求N!因子的个数,乘性函数,分解n!的质因子)

题目链接:http://poj.org/problem?id=2992

题目要求: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?

题目解析:这题也是TLE了无数遍,首先说一下求因子数目的函数是积性函数,积性函数即f(n)=f(a)*f(b),a与b互质并且a*b==n,因为n很大,所以要利用积性函数的性质,将n分解质因数,然后求其质因数的因子和,之后相乘即可,公式如下:

定理:设正整数n的所有素因子分解n=p1^a1*p2^a2*p3^a3****Ps^as,那么

T(n)=(a1+1)*(a2+1)*(a3+1)***(an+1);(求因子的个数的公式)

这题是求Cnk. 直接求肯定超时,所以要找规律,我没有找到,看了大神的题解,求N!质因子的规律如下,

首先,我们可以把所有的N以内的质数给打表求出来

然后,求每一个质因子的指数个数,这里用到了一个公式,:

ei=[N/pi^1]+ [N/pi^2]+ …… + [N/pi^n]  其中[]为取整

附:这一步最近又想到了一个更好的方法  int ei=0;while(N)  ei+=(N/=pi);   怎么样??

(想一想为什么,实在想不通你就举个例子试一下)

最后,就是套公式计算了,M=(e1+1)*(e2+1)*……*(en+1)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define N 500
using namespace std;
typedef long long ll;
bool b[N];
int n,k,i,num[N],prime[N],top;
__int64 sum;
int main()
{
    top=0;
    b[0]=b[1]=false;
    b[2]=true;
    for(i=3; i<440; i++)
        if(i%2==0) b[i]=false;
        else b[i]=true;
    double t=sqrt(440*1.0);
    for(i=3; i<=t; i++)
    {
        if(b[i])
        {
            for(int j=i*i; j<440; j=j+i)
                b[j]=false;
        }
    }
    for(i=2;i<=440;i++)
    {
        if(b[i])
        {
            prime[top++]=i;
        }
    }
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        sum=1;
        memset(num,0,sizeof(num));
        int X=0,t,z;
        for(i=prime[0];i<=n;i=prime[++X])
        {
            t=n;
            z=i;
            while(t/z)//核心部分
            {
                num[i]+=t/z;
                z*=i;
            }
        }
        X=0;
        for(i=prime[0];i<=n-k;i=prime[++X])
        {
            t=n-k;
            z=i;
            while(t/z)
            {
                num[i]-=t/z;
                z*=i;
            }
        }
        X=0;
        for(i=prime[0];i<=k;i=prime[++X])
        {
            t=k;
            z=i;
            while(t/z)
            {
                num[i]-=t/z;
                z*=i;
            }
        }
        for(int i=2; i<=n; i++)
        {
            if(num[i])
            {
                sum*=(num[i]+1);
            }
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

暴力到死的代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define N 500
using namespace std;
typedef long long ll;

int n,k,i;
int num[N];
ll sum;
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        sum=1;
        memset(num,0,sizeof(num));
        if(k>n/2)
          k=n-k;
        for(int z=n-k+1;z<=n;z++)
        {
            i=z;
            for(int j=2;j*j<=i;j++)
            {
                if(i%j==0)
                {
                    num[j]++;
                    i/=j;
                    while(i%j==0)
                    {
                        num[j]++;
                        i/=j;
                    }
                }
            }
            if(i!=1)
            num[i]++;
        }
        for(int z=2;z<=k;z++)
        {
            i=z;
            for(int j=2;j*j<=i;j++)
            {
                if(i%j==0)
                {
                    num[j]--;
                    i/=j;
                    while(i%j==0)
                    {
                        num[j]--;
                        i/=j;
                    }
                }
            }
            if(i!=1)
            num[i]--;
        }
        for(int i=2;i<=n;i++)
        {
            if(num[i])
            {
                num[i]++;
                //printf("___%d  %d\n",i,num[i]);
            }

        }
        for(int i=2;i<=n;i++)
        {
            if(num[i])
            {
               sum*=num[i];
            }
        }
        printf("%lld\n",sum);
    }
    return 0;
}

时间: 2024-10-13 07:32:26

POJ2992:Divisors(求N!因子的个数,乘性函数,分解n!的质因子)的相关文章

poj2992 divisors 求组合数的约数个数,阶乘的质因数分解

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 containin

hdu 6069 Counting Divisors(求因子的个数)

Counting Divisors Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 3170    Accepted Submission(s): 1184 Problem Description In mathematics, the function d(n) denotes the number of divisors of

Poj2992Divisors 组合数求因子的个数

Divisors 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

(hdu step 2.1.3)Largest prime factor(求一个数的最大质因子的位置)

题目: Largest prime factor Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4868 Accepted Submission(s): 1452   Problem Description Everybody knows any number can be combined by the prime number.Now,

求一个数的质因子

private static void prime(int i){ int j = 2; while(true){ while(i%j == 0 && i != j){ System.out.println("Prime num " + j); i = i/j; } if(i == j){ System.out.println("Prime num " + j); break; } j++; } } private static void prime

LightOj 1278 - Sum of Consecutive Integers(求奇因子的个数)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1278 题意:给你一个数n(n<=10^14),然后问n能用几个连续的数表示; 例如: 15 = 7+8 = 4+5+6 = 1+2+3+4+5,所以15对应的答案是3,有三种; 我们现在相当于已知等差数列的和sum = n, 另首项为a1,共有m项,那么am = a1+m-1: sum = m*(a1+a1+m-1)/2  -----> a1 = sum/m - (m-1)/2 a

POJ 2992-Divisors(求组合数质因子的个数)

Divisors Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2992 Appoint description:  System Crawler  (2015-04-24) Description Your task in this problem is to determine the number of divisors of C

XDU1019 阶乘因子的个数

题意是让你求一个最小的N, 使得N!有M个0,N的阶乘中2的因子是远多于5的因子的个数, 因此我们统计出5的个数就知道其后面有几个0,对于一个数mid, mid!中5的因子的个数为mid/5 + mid/25 + mid/5^3 + ... 可以发现mid越大mid!中的5的个数越多, 因此我们可以二分答案, 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <iost

Factorial Trailing Zeroes(析因,求尾随个0个数)

Given an integer n, return the number of trailing zeroes in n! 这是LeetCode Online Judge上的一个原题:给定一个n,求n!中,末尾0的个数. 思路 n!中0的个数,可以将n!表示成 n!=m*10k,其中k就是题目要求的结果.那么,10k是怎么来的呢?很容易想到,10=2*5,那么,10k=(2*5)k:至此,可以简化成,题目求的是2*5的个数: 进一步思考,1*2*3……(n-1)*n,求2*5的个数就是求1-n