题目大意: 问有多少个值不相同的分数 x y ( x ∈ [ 1 , n ] , y ∈ [ 1 , m ] ) \dfrac x y(x\in[1,n],y\in[1,m]) yx(x∈[1,n],y∈[1,m]),满足在 k k k 进制下是个纯循环小数。纯循环:即小数存在循环节(可以是 0 0 0),且从小数点后第一位就开始循环。
题解
假设 k k k 为 10 10 10,循环节为 x 1 x 2 . . . x c x_1x_2...x_c x1x2...xc,那么小数点部分就可以表示为这样的分数: x 1 x 2 . . . x c 999...99 \dfrac {x_1x_2...x_c} {999...99} 999...99x1x2...xc,下面是 c c c 个 9 9 9。
也就是说,对于分数 x y \dfrac x y yx,只有当 y y y 的某个倍数是若干个 9 9 9 时, x y \dfrac x y yx 才是纯循环小数。
c c c 个 9 9 9 组成的数可以表示成 1 0 c − 1 10^c-1 10c−1,也就是要存在一个 c c c 满足 y ∣ ( 1 0 c − 1 ) y|(10^c-1) y∣(10c−1),这个东西可以转化成 1 0 c ≡ 1 ( m o d y ) 10^c\equiv 1\pmod y 10c≡1(mody),根据扩欧,只有当 10 10 10 和 y y y 互质时, 10 10 10 才存在逆元,也就是存在满足条件的 c c c。
类似的,我们可以得到,只有当 y ⊥ k y\perp k y⊥k 时, x y \dfrac x y yx 才是纯循环小数。
那么此时已经可以写出答案式子了:
∑
i
=
1
n
∑
j
=
1
m
[
i
⊥
j
]
[
j
⊥
k
]
\sum_{i=1}^n\sum_{j=1}^m[i\perp j][j\perp k]
i=1∑nj=1∑m[i⊥j][j⊥k]
对
[
i
⊥
j
]
[i\perp j]
[i⊥j] 使用莫反,得到:
=
∑
i
=
1
n
∑
j
=
1
m
[
j
⊥
k
]
∑
d
∣
gcd
(
i
,
j
)
μ
(
d
)
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
∑
i
=
1
n
[
d
∣
i
]
∑
j
=
1
m
[
d
∣
j
]
[
j
⊥
k
]
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
[
d
⊥
k
]
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
j
⊥
k
]
\begin{aligned} &=\sum_{i=1}^n\sum_{j=1}^m [j\perp k]\sum_{d|\gcd(i,j)}\mu(d)\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{i=1}^n[d|i]\sum_{j=1}^m[d|j][j\perp k]\\ &=\sum_{d=1}^{\min(n,m)}\mu(d) [d\perp k] \lfloor \frac n d \rfloor\sum_{j=1}^{\lfloor \frac m d \rfloor}[j\perp k] \end{aligned}
=i=1∑nj=1∑m[j⊥k]d∣gcd(i,j)∑μ(d)=d=1∑min(n,m)μ(d)i=1∑n[d∣i]j=1∑m[d∣j][j⊥k]=d=1∑min(n,m)μ(d)[d⊥k]⌊dn⌋j=1∑⌊dm⌋[j⊥k]
一开始尝试往另外两个互质上套莫反,然而发现会越推越丑……所以直接考虑从这个式子入手求解。
注意到里面有一个 ⌊ n d ⌋ \lfloor \dfrac n d\rfloor ⌊dn⌋,这提示我们进行整除分块,假如能对另外两个部分进行快速的前缀求和,那么就可以套整除分块了。
设 g ( n , k ) = ∑ i = 1 n μ ( i ) [ i ⊥ k ] , f ( n , k ) = ∑ i = 1 n [ i ⊥ k ] g(n,k)=\sum_{i=1}^n \mu(i)[i\perp k],f(n,k)=\sum_{i=1}^n [i\perp k] g(n,k)=∑i=1nμ(i)[i⊥k],f(n,k)=∑i=1n[i⊥k],注意到如果 k k k 有 > 1 >1 >1 个质因子 p i p_i pi,那么只保留一个其他全部除掉是不会影响这两个式子的,分析一下互质的性质就能发现,于是我们预处理一下这个 k k k,现在 k k k 满足不包含平方因子。
f
,
g
f,g
f,g 没有什么很好的直接求的方法,所以只能尝试递推。对于
k
k
k 的一个质因子
p
p
p,考虑除掉
p
p
p 之后答案的变化,先看
f
f
f:
f
(
n
,
k
)
=
∑
i
=
1
n
[
i
⊥
k
]
=
∑
i
=
1
n
[
i
⊥
k
p
]
−
∑
i
=
1
n
[
p
∣
i
]
[
i
⊥
k
p
]
=
f
(
n
,
k
p
)
−
∑
i
=
1
⌊
n
p
⌋
[
i
p
⊥
k
p
]
=
f
(
n
,
k
p
)
−
∑
i
=
1
⌊
n
p
⌋
[
i
⊥
k
p
]
=
f
(
n
,
k
p
)
−
f
(
⌊
n
p
⌋
,
k
p
)
\begin{aligned} f(n,k)&=\sum_{i=1}^n [i\perp k]\\ &=\sum_{i=1}^n [i\perp \frac k p]-\sum_{i=1}^n [p|i][i\perp \frac k p]\\ &=f(n,\frac k p)-\sum_{i=1}^{\lfloor \frac n p \rfloor}[ip\perp \frac k p]\\ &=f(n,\frac k p)-\sum_{i=1}^{\lfloor \frac n p \rfloor}[i\perp \frac k p]\\ &=f(n,\frac k p)-f(\lfloor \frac n p\rfloor,\frac k p) \end{aligned}
f(n,k)=i=1∑n[i⊥k]=i=1∑n[i⊥pk]−i=1∑n[p∣i][i⊥pk]=f(n,pk)−i=1∑⌊pn⌋[ip⊥pk]=f(n,pk)−i=1∑⌊pn⌋[i⊥pk]=f(n,pk)−f(⌊pn⌋,pk)
中间
[
i
p
⊥
k
p
]
=
[
i
⊥
k
p
]
[ip\perp \dfrac k p]=[i\perp \dfrac k p]
[ip⊥pk]=[i⊥pk] 这一步就用到了k没有平方因子
这个性质。
g
g
g 的递推是类似的:
g
(
n
,
k
)
=
∑
i
=
1
n
μ
(
i
)
[
i
⊥
k
]
=
∑
i
=
1
n
μ
(
i
)
[
i
⊥
k
p
]
−
∑
i
=
1
n
μ
(
i
)
[
p
∣
i
]
[
i
⊥
k
p
]
=
g
(
n
,
k
p
)
−
∑
i
=
1
⌊
n
p
⌋
μ
(
i
p
)
[
i
p
⊥
k
p
]
\begin{aligned} g(n,k)&=\sum_{i=1}^n \mu(i)[i\perp k]\\ &=\sum_{i=1}^n \mu(i)[i\perp \frac k p]-\sum_{i=1}^n\mu(i)[p|i][i\perp \frac k p]\\ &=g(n,\frac k p)-\sum_{i=1}^{\lfloor \frac n p \rfloor} \mu(ip)[ip\perp \frac k p] \end{aligned}
g(n,k)=i=1∑nμ(i)[i⊥k]=i=1∑nμ(i)[i⊥pk]−i=1∑nμ(i)[p∣i][i⊥pk]=g(n,pk)−i=1∑⌊pn⌋μ(ip)[ip⊥pk]
μ \mu μ 有一个性质, μ ( i j ) = μ ( i ) μ ( j ) [ i ⊥ j ] \mu(ij)=\mu(i)\mu(j)[i\perp j] μ(ij)=μ(i)μ(j)[i⊥j],证明的话,若不满足 i ⊥ j i\perp j i⊥j,那么 i j ij ij 就含有平方因子,则 μ ( i j ) = 0 \mu(ij)=0 μ(ij)=0;如果满足那么根据积性函数定义就显然可以拆开。
代入得到:
=
g
(
n
,
k
p
)
−
∑
i
=
1
⌊
n
p
⌋
μ
(
i
)
μ
(
p
)
[
i
⊥
p
]
[
i
⊥
k
p
]
=
g
(
n
,
k
p
)
+
∑
i
=
1
⌊
n
p
⌋
μ
(
i
)
[
i
⊥
k
]
=
g
(
n
,
k
p
)
+
g
(
⌊
n
p
⌋
,
k
)
\begin{aligned} &=g(n,\frac k p)-\sum_{i=1}^{\lfloor \frac n p\rfloor}\mu(i)\mu(p)[i\perp p][i\perp \frac k p]\\ &=g(n,\frac k p)+\sum_{i=1}^{\lfloor \frac n p\rfloor}\mu(i)[i\perp k]\\ &=g(n,\frac k p)+g(\lfloor \frac n p\rfloor,k) \end{aligned}
=g(n,pk)−i=1∑⌊pn⌋μ(i)μ(p)[i⊥p][i⊥pk]=g(n,pk)+i=1∑⌊pn⌋μ(i)[i⊥k]=g(n,pk)+g(⌊pn⌋,k)
f , g f,g f,g 的个数是 n × log k log log k \sqrt n\times \dfrac {\log k} {\log\log k} n×loglogklogk 的,记忆化一下递推就好,当 k = 1 k=1 k=1 时, f ( n , k ) f(n,k) f(n,k) 显然为 n n n, g ( n , k ) g(n,k) g(n,k) 就是 μ \mu μ 的前 n n n 项之和,弄一个杜教筛就好。
然而存 f , g f,g f,g 时我写的哈希冲突很多所以跑得飞慢,最后直接换了map反而来的快……代码如下:
#include <bits/stdc++.h>
using namespace std;
#define maxn 3000010
int n,m,k;
int prime[maxn],t=0,mu[maxn];
bool v[maxn];
void SieveInit(){
mu[1]=1;
for(int i=2;i<=maxn-10;i++){
if(!v[i])prime[++t]=i,mu[i]=-1;
for(int j=1;j<=t&&i*prime[j]<=maxn-10;j++){
v[i*prime[j]]=true;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
mu[i]+=mu[i-1];
}
}
map<int,int> Smu;
struct par{
int x,y;
bool operator <(const par &B)const{return x==B.x?y<B.y:x<B.x;}
};
map<par,int> f,g;
int calc_mu(int x){
if(x<=maxn-10)return mu[x];
if(Smu.count(x))return Smu[x];
long long tot=1;
for(int l=2,r;l<=x;l=r+1){
r=x/(x/l);
tot-=calc_mu(x/l)*(r-l+1);
}
Smu[x]=tot;
return tot;
}
int fac[maxn];
int calc_f(int x,int y){
if(x==0)return 0;
if(y==1)return x;
par p=(par){x,y};int re;
if(f.count(p))return f[p];
re=calc_f(x,y/fac[y])-calc_f(x/fac[y],y/fac[y]);
f[p]=re;
return re;
}
int calc_g(int x,int y){
if(x==0)return 0;
if(y==1)return calc_mu(x);
par p=(par){x,y};int re;
if(g.count(p))return g[p];
re=calc_g(x,y/fac[y])+calc_g(x/fac[y],y);
g[p]=re;
return re;
}
int main()
{
scanf("%d %d %d",&n,&m,&k);SieveInit();
for(int i=2;i<=k;i++)//去掉多余的质因子
while(k%(i*i)==0)k/=i;
int k_=k;for(int i=2;i<=k;i++)
if(k_%i==0)fac[k_]=i,k_/=i;
long long ans=0;
for(int l=1,r;l<=min(n,m);l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=1ll*(calc_g(r,k)-calc_g(l-1,k))*(n/l)*calc_f(m/l,k);
}
printf("%lld",ans);
}