https://vjudge.net/contest/307652#problem/H
题意
t组数据(t<=200),1<=n<=1e14,求n以内的lcm(i,j)==n的对数,i<=j
题解
根据唯一分解定理,有一下两个关于gcd和lcm的式子,这也是求gcd和lcm的一种方法:
a=p1 ^ a1 * p2 ^ a2 *…*pn ^ an
b=p1 ^ b1 * p2 ^ b2 *…*pn ^ bn
gcd(a,b)=p1 ^ min(a1,b1) * p2 ^ min(a2,b2) *…*pn ^ min(an,bn)
lcm(a,b)=p1 ^ max(a1,b1) * p2 ^ max(a2,b2) *…*pn ^ max(an,bn)
对于每一个ei,只需ai或bi等于ei,另一个小于等于ei即可,则有2*(ei+1)中取法,ai=bi=ei取了俩次,减1即为2*ei+1,共π(2ei+1)种。
π(2ei+1)必定为奇数,里面除(n,n)之外都取了两次,因为要求i<=j,所以答案为π(2ei+1)/2+1
代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=(1e7+5);
bool isprime[maxn];
int su[670000];
int cnt;
void init()
{
cnt=0;
isprime[0]=isprime[1]=1;
for(int i=2;i<maxn;i++)
{
if(isprime[i]==0)
su[cnt++]=i;
for(int j=0;j<cnt&&i*su[j]<maxn;j++)
{
isprime[i*su[j]]=1;
if(i%su[j]==0)
break;
}
}
}
ll fj(ll x)
{
ll fact=1;
for(int i=0;i<cnt&&su[i]<=sqrt(x);i++)
{
ll num=0;
while(x%su[i]==0)
{
num++;
x/=su[i];
}
fact*=((ll)2*num+(ll)1);
}
if(x>1)
fact*=3;
return fact;
}
int main()
{
init();
int t,cmt=0;
ll n;
scanf("%d",&t);
while(t--)
{
cmt++;
scanf("%lld",&n);
ll fact=fj(n);
fact=fact/2+1;
printf("Case %d: %lld\n",cmt,fact);
}
return 0;
}