hoj 1560 - Factovisors

 http://acm.hit.edu.cn/ojs/show.php?Proid=1560&Contestid=0

        先处理一些特殊情况

  1. m = 0 时一定不能整除 ;
  2. n >= m 一定能整除;

     其他情况做法如下:先对m分解质因数,并记录每个质因子和其个数,在判断n!是否含有这些质因子

     下面说一下对m分解质因数的方法.首先生成一个素数表.因m为一个小于232的整型数,且232的平方根小于47000,所以我们的素数表只需求到47000即可,而小于47000的素数有4851个,因此素数表的大小应不小于4851.之后用素数表中的每一个素数试除m,求出m的每个质因子和其相应的个数.如果最后的商不等于1,那么这个商也是m的质因子,且它一定大于47000.

     另外解题过程中需用到这个结论:对于任意的质数p, n!中有(n / p + n / p2 + n / p3 + … )个质因子p.

附代码

#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <functional>
#include <vector>
 
using namespace std;
int main()
{
    int prime[4900] = {2, 3}, pn = 2, i, j, n, m, m0; int n0, a[4900], an[4900], anum;
    long long sum;
    bool divide;
 
    for (i = 5; i <= 47000; i += 2)
    {
        for (j = 1; prime[j] * prime[j] < i; j++)
        {
            if (i % prime[j] == 0)
            {
                break;
            }
        }
        if (i % prime[j] != 0)
        {
            prime[pn++] = i;
        }
    }
 
    while (scanf("%d%d", &n, &m) == 2)
    {
        if (m == 0)
        {
            divide = false;
        }
        else if (n >= m)
        {
            divide = true;
        }
        else
        {
            m0 = m;
            anum = 0;
            memset(an, 0, sizeof(an));
            for (i = 0; i < pn && prime[i] <= m; i++)
            {
                if (m0 % prime[i] == 0)
                {
                    a[anum] = prime[i];
                    while (m0 % prime[i] == 0)
                    {
                        an[anum]++;
                        m0 /= prime[i];
                    }
                    anum++;
                }
                if (m0 == 1)
                {
                    break;
                }
            }
 
            if (m0 > 1)
            {
                a[anum] = m0;
                an[anum++]++;
            }
 
            divide = true;
            for (i = 0; i < anum; i++)
            {
                sum = 0;
                if (a[i] > n)
                {
                    divide = false;
                    break;
                }
                else
                {
                    n0 = n;
                    while (n0 > 0)
                    {
                        sum += n0 / a[i];
                        n0 /= a[i];
                        if (sum >= an[i])
                        {
                            break;
                        }
                    }
                    if (sum < an[i])
                    {
                        divide = false;
                        break;
                    }
                }
            }
 
        }
 
        if (divide)
        {
            printf("%d divides %d!/n", m, n);
        }
        else
        {
            printf("%d does not divide %d!/n", m, n);
        }
    }
 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值