题目描述如下:
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用于判断是否储存
}
}
本题也就说到这儿了,接触数论不久很多地方不专业~欢迎留言评论我会尽力解答