当前位置: 代码迷 >> 综合 >> LightOJ - 1236 Pairs Forming LCMPairs Forming LCM(唯一分解定理+LCM)
  详细解决方案

LightOJ - 1236 Pairs Forming LCMPairs Forming LCM(唯一分解定理+LCM)

热度:95   发布时间:2023-12-09 20:16:56.0

链接:LightOJ - 1236 Pairs Forming LCMPairs Forming LCM

题意:

给出正整数 n n n,问有多少对 ( a , b ) (a,b) (a,b)满足 l c m ( a , b ) = n lcm(a,b)=n lcm(a,b)=n a ≤ b ≤ n a\le b\le n abn



分析:

这就涉及到gcd和lcm的另一种表示方法了,对于 a , b a,b a,b,根据唯一分解定理得到标准分解式:

a = p 1 a 1 ? p 2 a 2 ? p 3 a 3 ? p n a n a=p_1^{a_1}\cdot p_2^{a_2}\cdot p_3^{a_3} \cdots p_n^{a_n} a=p1a1???p2a2???p3a3???pnan??

b = p 1 b 1 ? p 2 b 2 ? p 3 b 3 ? p n b n b=p_1^{b_1}\cdot p_2^{b_2}\cdot p_3^{b_3} \cdots p_n^{b_n} b=p1b1???p2b2???p3b3???pnbn??

那么有 gcd ? ( a , b ) = p 1 min ? ( a 1 , b 1 ) ? p 2 min ? ( a 2 , b 2 ) ? p 3 min ? ( a 3 , b 3 ) ? p n min ? ( a n , b n ) \gcd(a,b)=p_1^{\min(a_1,b_1)}\cdot p_2^{\min(a_2,b_2)}\cdot p_3^{\min(a_3,b_3)}\cdots p_n^{\min(a_n,b_n)} gcd(a,b)=p1min(a1?,b1?)??p2min(a2?,b2?)??p3min(a3?,b3?)??pnmin(an?,bn?)?
l c m ( a , b ) = p 1 max ? ( a 1 , b 1 ) ? p 2 max ? ( a 2 , b 2 ) ? p 3 max ? ( a 3 , b 3 ) ? p n max ? ( a n , b n ) lcm(a,b)=p_1^{\max(a_1,b_1)}\cdot p_2^{\max(a_2,b_2)}\cdot p_3^{\max(a_3,b_3)}\cdots p_n^{\max(a_n,b_n)} lcm(a,b)=p1max(a1?,b1?)??p2max(a2?,b2?)??p3max(a3?,b3?)??pnmax(an?,bn?)?
所以对于该题,可以将 n n n分解,得到 n = p 1 e 1 ? p 2 e 2 ? p 3 e 3 ? p n e n n=p_1^{e_1}\cdot p_2^{e_2}\cdot p_3^{e_3} \cdots p_n^{e_n} n=p1e1???p2e2???p3e3???pnen??

先不考虑 a a a b b b的大小关系;

对于 p i p_i pi? a i a_i ai? b i b_i bi?要至少有一个等于 e i e_i ei?,另一个要 ≤ e i \le e_i ei?,所以共有 2 ? ( e i + 1 ) ? 1 = 2 e i + 1 2*(e_i+1)-1=2e_i+1 2?(ei?+1)?1=2ei?+1种搭配;( ? 1 -1 ?1是因为 a i = b i = e i a_i=b_i=e_i ai?=bi?=ei?多算了一次)

所以总共的搭配数就是: r e s = ∏ i = 1 n ( 2 e i + 1 ) res=\displaystyle\prod_{i=1}^{n}(2e_i+1) res=i=1n?(2ei?+1)

最后,因为 a ≤ b a\le b ab,对称分布,所以有 r e s = r e s / 2 + 1 res=res/2+1 res=res/2+1



以下代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e7+50;
LL prime[1000000],tot;
bool vis[maxn];
void getprime()
{
    tot=0;for(LL i=2;i<=maxn;i++){
    if(!vis[i])prime[++tot]=i;for(LL j=1;j<=tot&&i*prime[j]<=maxn;j++){
    vis[i*prime[j]]=true;if(i%prime[j]==0)break;}}
}
LL solve(LL n)
{
    LL res=1,k=n;for(LL i=1;prime[i]*prime[i]<=k;i++){
    if(n%prime[i]==0){
    LL e=0;while(n%prime[i]==0){
    e++;n/=prime[i];}res*=2*e+1;}}if(n>1)res*=2*1+1;return res/2+1;
}
int main()
{
    getprime();int T,kase=0;scanf("%d",&T);while(T--){
    LL n;scanf("%lld",&n);printf("Case %d: %lld\n",++kase,solve(n));}return 0;
}