求幂
传送门
题意:寻找有多少对
a
a
a、
b
b
b、
c
c
c、
d
∈
[
1
,
n
]
d\in[1,n]
d∈[1,n],满足
a
b
=
c
d
a^b=c^d
ab=cd。
思路:
看似简单的题目往往都暗藏玄机。
本思路参考题解。
主要操作:
第一步,用唯一分解定理将原式简化为
(
i
j
)
x
=
(
i
k
)
y
(i^j)^x=(i^k)^y
(ij)x=(ik)y。
第二步,按照范围枚举
i
i
i、
j
j
j、
k
k
k。
第三步,找到
i
j
i^j
ij和
i
k
i^k
ik的最小公倍数,求得满足
(
i
j
)
x
=
(
i
k
)
y
(i^j)^x=(i^k)^y
(ij)x=(ik)y且
x
x
x、
y
∈
[
1
,
n
]
y\in[1,n]
y∈[1,n]的
x
x
x个数(ie.
y
y
y的个数)。
具体原理:
很容易想到,一开始要将
A
A
A和
C
C
C用唯一分解定理表示。由于他们的某个幂相等,易得他们分解出来的质数是一一对应的。即
A
=
q
1
a
1
+
q
2
a
2
+
.
.
.
+
q
p
a
p
A=q_{1}^{a_1}+q_{2}^{a_2}+...+q_{p}^{a_p}
A=q1a1+q2a2+...+qpap,
C
=
q
1
b
1
+
q
2
b
2
+
.
.
.
+
q
p
b
p
C=q_{1}^{b_1}+q_{2}^{b_2}+...+q_{p}^{b_p}
C=q1b1+q2b2+...+qpbp。并且有
a
i
×
B
=
b
i
×
D
,
i
∈
[
1
,
p
]
a_{i}\times B=b_i\times D,i\in[1,p]
ai×B=bi×D,i∈[1,p]。我们设最简分数
m
n
=
d
b
=
a
i
b
i
\frac{m} n=\frac d b=\frac {a_i}{b_i}
nm=bd=biai,设
i
=
q
1
a
1
m
+
q
2
a
2
m
+
.
.
.
+
q
p
a
p
m
=
q
1
b
1
n
+
q
2
b
2
n
+
.
.
.
+
q
p
b
p
n
i=q_{1}^{\frac {a_1}{m}}+q_{2}^{\frac {a_2}{m}}+...+q_{p}^{\frac {a_p}{m}}=q_{1}^{\frac {b_1}{n}}+q_{2}^{\frac {b_2}{n}}+...+q_{p}^{\frac {b_p}{n}}
i=q1ma1+q2ma2+...+qpmap=q1nb1+q2nb2+...+qpnbp称为 “公共基底数”,原式就等价于
(
i
m
)
b
=
(
i
n
)
d
(i^m)^b=(i^n)^d
(im)b=(in)d。
为了直观,把
m
m
m换成
j
j
j,
n
n
n换成
k
k
k,
b
b
b换成
x
x
x,
d
d
d换成
y
y
y。根据条件,要求
i
j
i^j
ij和
i
k
i^k
ik小于等于
n
n
n,
x
x
x、
y
y
y小于等于
n
n
n。
(
i
j
)
x
=
(
i
k
)
y
(i^j)^x=(i^k)^y
(ij)x=(ik)y意味着
j
×
x
=
k
×
y
j\times x=k\times y
j×x=k×y,我们首先遍历
i
i
i、
j
j
j、
k
k
k,然后要找到满足这个关系的
x
x
x和
y
y
y的对数。很好找,只需要求
j
j
j与
k
k
k的最小公倍数,在最小公倍数的基础上乘正整数,直到
x
x
x和
y
y
y任意一个大于
n
n
n。设正整数为
q
q
q,
q
q
q的最大值就等于满足这个关系的
x
x
x和
y
y
y的对数。
q
×
l
c
m
(
j
,
k
)
=
j
×
x
=
k
×
y
≤
j
×
n
,
k
×
n
q\times lcm(j,k)=j\times x=k\times y\le{j\times n},{k\times n}
q×lcm(j,k)=j×x=k×y≤j×n,k×n,于是,
q
≤
m
i
n
(
j
×
n
l
c
m
,
k
×
n
l
c
m
)
q\le{min}(\frac{j\times n}{lcm},\frac{k\times n}{lcm})
q≤min(lcmj×n,lcmk×n)。
实现:
有三个地方需要注意:
(1)
i
=
1
i=1
i=1要特判,不然幂次运算陷入死循环。
(2)用vis数组判重,减少重复计算,寻找
i
j
i^j
ij和
i
k
i^k
ik的上限的时候,把经过的都标记一下就行了。
(3)如果直接用
j
×
n
j\times n
j×n来算,会爆,又因为\符号自带floor功能,不能先除lcm再乘。于是选择直接拿gcd,
j
×
n
l
c
m
=
g
c
d
×
j
×
n
j
×
k
=
g
c
d
×
n
k
=
n
k
g
c
d
\frac{j\times n}{lcm}=\frac{gcd\times j\times n}{j\times k}=\frac{gcd\times n}{k}=\frac{n}{\frac{k}{gcd}}
lcmj×n=j×kgcd×j×n=kgcd×n=gcdkn。众所周知,
k
g
c
d
\frac{k}{gcd}
gcdk为一整数。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
bool vis[1000004];
inline int read(){
int k=0,j=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') j=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){k=(k<<1)+(k<<3)+ch-'0';ch=getchar();}
return k*j;
}
ll gcd(ll a,ll b){
if(b==0) return a;
else return gcd(b,a%b);
}
int main(){
ll n=(long long)read();
ll ans=(n*n)%mod;//特判
//开始遍历i
for(ll i=2;i<=n;i++){
if(vis[i]) continue;
ll maxn=1;//不超过n的最大的幂次
ll now=i;//幂次后的数
while(now<=n/i){
maxn++;
now*=i;
vis[now]=1;//确定可达,才标记
}
for(ll j=1;j<=maxn;j++){
for(ll k=1;k<=maxn;k++){
ll g=gcd(j,k);
ll tmp=k/g,tmp2=j/g;
ans=(ans+min(n/tmp,n/tmp2))%mod;
}
}
}
printf("%lld\n",ans);
}