UVA—LCM Cardinality(基础数论)

15 篇文章 0 订阅
1 篇文章 0 订阅

题目描述如下:

LCM Cardinality

A pair of numbers has a unique LCM but a single number can be the LCM of more than one possible
pairs. For example 12 is the LCM of (1, 12), (2, 12), (3,4) etc. For a given positive integer N, the
number of different integer pairs with LCM is equal to N can be called the LCM cardinality of that
number N. In this problem your job is to find out the LCM cardinality of a number.
Input
The input file contains at most 101 lines of inputs. Each line contains an integer N (0 < N ≤ 2 ∗ 109
).
Input is terminated by a line containing a single zero. This line should not be processed.
Output
For each line of input except the last one produce one line of output. This line contains two integers
N and C. Here N is the input number and C is its cardinality. These two numbers are separated by a
single space.

Sample Input
2
12
24
101101291
0

Sample Output
2 2
12 8
24 11
101101291 5


题意:

这道题其实就是求对于一个整数n,有对少对<=n的两个数a,b,使它们的最小公倍数为n。

思路:

质数拆分。
即对于一个整数a,b,我们可以将它写成:a=(p1 ^ k1)x(p2 ^ k2)x(p3 ^ k3)……
同理,b=(p1 ^ k1)x(p2 ^ k2)x(p3 ^ k3)…(eg:72=2 ^ 3 * 3 ^ 2)
那么可以得到:
gcd(a,b)=p1 ^ min(k1a,k1b) x p2^min(k2a,k2b)…
lcm(a,b)=p1 ^ max(k1a,k1b) x p2^max(k2a,k2b)…(不要问我为什么这样我也不清楚,qaq,太菜了,网上查了很多资料发现这个结论)
那么对于任意一个质数p,若k已经固定,(假设取a的k)则b一共有0~k-1,一共k种;同理若取b,则a有k种。再加上a,b相等的一种,所以对于每一个k,一共有2xk+1种方法。
同时还要注意一点,如果最终得到的N(分解完后)不为1(1不用考虑,每个数可以分解出无数个1),则说明最终得到的一个N已经是一个质数,可以写成N ^ 1,k=1,则最后还需要乘以3即可。现在可以开始写代码了。

#include<cstdio>
#include<cmath>
using namespace std;
int n,cn,tot,ans;
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        cn=n;ans=1;
        for(int i=2;i<=sqrt(cn)&&i<=n;i++)
        {
            if(n%i==0)
            {
                tot=0;
                while(n%i==0){n/=i;tot++;}
                ans=ans*(2*tot+1);
            }
        }
        if(n>1)ans*=3;//说明还剩下一个质数,表示为p^1,为三种
        printf("%d %d\n",cn,ans/2+1);//只算一种,因为默认了b为n,只求一边的情况,即a<=b时的情况
    }
    return 0;
}

老实说虽然用sqrt()进行了优化,但是效率还是不算太高,总之这个平台ac了,其他平台不知道怎么样。如果还想大幅度提升效率我们还可以素数筛法进行优化。素数筛法如下,有兴趣可以合着试一下,这里我就不合并了:

int prime[100001],cnt,n;
bool isprime[100001];
void getprime()///原理:一个非素数一定可以分解为前面若干个数的乘积
{
    isprime[0]=isprime[1]=true;
    for(int i=2;i<=n;i++)///n是输入的数
    {
        if(!isprime[i])prime[++cnt]=i;///保存素数
        for(int j=1;j<=cnt&&prime[j]*i<100001;++j)
            isprime[i*prime[j]]=true;///将它的整数倍全部排除,isprime用于判断是否储存
    }
}

本题也就说到这儿了,接触数论不久很多地方不专业~欢迎留言评论我会尽力解答

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值