Description
- 给定十进制数 n , m , k n, m, k n,m,k,求在 k k k 进制下有多少个 值不相等 的 纯循环 小数可以用分数 x y \dfrac{x}{y} yx 表示,其中 1 ≤ x ≤ n , 1 ≤ y ≤ m , x , y ∈ N ∗ 1\le x\le n, 1\le y\le m, x, y \in \mathbb{N}^* 1≤x≤n,1≤y≤m,x,y∈N∗。
- 1 ≤ n , m ≤ 1 0 9 , 2 ≤ k ≤ 2 × 1 0 3 1\le n, m\le 10^9, 2\le k\le 2\times 10^3 1≤n,m≤109,2≤k≤2×103。
Solution
Step 1:转化问题
首先这些数的值要互不相等,那不妨只计算满足要求的 最简分数 的数量,即 gcd ( x , y ) = 1 \gcd(x, y) = 1 gcd(x,y)=1。
根据你丰富的小奥知识得到:如果在 k k k 进制下分数 x y \dfrac{x}{y} yx 为最简分数,则 gcd ( y , k ) = 1 \gcd(y, k) = 1 gcd(y,k)=1 是其可化成纯循环小数的 充要条件。
证明:
设 x y \dfrac{x}{y} yx 化成的纯循环小数的循环节长度为 l l l,则有 { x y } = { x y ⋅ k l } \left\{\dfrac{x}{y} \right\} = \left\{\dfrac{x}{y} \cdot k^l \right\} {yx}={yx⋅kl}。
乘 k l k^l kl 其实就是将小数点向后移动 l l l 位,小数部分还是不变的。
根据 { x } = x − ⌊ x ⌋ \{x\} = x - \lfloor x\rfloor {x}=x−⌊x⌋,有
x y − ⌊ x y ⌋ = x k l y − ⌊ x k l y ⌋ x − ⌊ x y ⌋ y = x k l − ⌊ x k l y ⌋ y x ≡ x k l ( m o d y ) ∵ gcd ( x , y ) = 1 ∴ k l ≡ 1 ( m o d y ) ∴ gcd ( y , k ) = 1 \dfrac{x}{y} - \left\lfloor\dfrac{x}{y}\right\rfloor = \dfrac{x k^l}{y} - \left\lfloor\dfrac{x k^l}{y}\right\rfloor \\ x - \left\lfloor\dfrac{x}{y}\right\rfloor y = x k^l - \left\lfloor\dfrac{x k^l}{y} \right\rfloor y \\ x \equiv x k^l \pmod y \\ \because \gcd(x, y) = 1 \\ \therefore k^l \equiv 1 \pmod y \\ \therefore \gcd(y, k) = 1 yx−⌊yx⌋=yxkl−⌊yxkl⌋x−⌊yx⌋y=xkl−⌊yxkl⌋yx≡xkl(mody)∵gcd(x,y)=1∴kl≡1(mody)∴gcd(y,k)=1
所以我们要求的其实就是
∑
x
=
1
n
∑
y
=
1
m
[
gcd
(
x
,
y
)
=
1
]
[
gcd
(
y
,
k
)
=
1
]
\sum_{x = 1}^n \sum_{y = 1}^m [\gcd(x, y) = 1] [\gcd(y, k) = 1]
x=1∑ny=1∑m[gcd(x,y)=1][gcd(y,k)=1]
Step 2:莫比乌斯反演
先将 x ⇔ i , y ⇔ j x \Leftrightarrow i, y \Leftrightarrow j x⇔i,y⇔j,不妨设 n ≤ m n\le m n≤m。
a
n
s
=
∑
i
=
1
n
∑
j
=
1
m
[
gcd
(
j
,
k
)
=
1
]
∑
d
∣
gcd
(
i
,
j
)
μ
(
d
)
=
∑
d
=
1
n
μ
(
d
)
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
gcd
(
j
d
,
k
)
=
1
]
=
∑
d
=
1
n
[
gcd
(
d
,
k
)
=
1
]
μ
(
d
)
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
gcd
(
j
,
k
)
=
1
]
\begin{aligned} ans & = \sum_{i = 1}^n \sum_{j = 1}^m [\gcd(j, k) = 1] \sum_{d\mid \gcd(i, j)} \mu(d) \\ & = \sum_{d = 1}^n \mu(d) \left\lfloor\dfrac{n}{d}\right\rfloor \sum_{j = 1}^{\left\lfloor\frac{m}{d}\right\rfloor} [\gcd(jd, k) = 1] \\ & = \sum_{d = 1}^n [\gcd(d, k) = 1] \mu(d) \left\lfloor\dfrac{n}{d}\right\rfloor \sum_{j = 1}^{\left\lfloor\frac{m}{d}\right\rfloor} [\gcd(j, k) = 1] \end{aligned}
ans=i=1∑nj=1∑m[gcd(j,k)=1]d∣gcd(i,j)∑μ(d)=d=1∑nμ(d)⌊dn⌋j=1∑⌊dm⌋[gcd(jd,k)=1]=d=1∑n[gcd(d,k)=1]μ(d)⌊dn⌋j=1∑⌊dm⌋[gcd(j,k)=1]
已经化到最简了,考虑设函数。
我们对
f
(
n
)
=
∑
i
=
1
n
[
gcd
(
i
,
k
)
=
1
]
f(n) = \sum_{i = 1}^n [\gcd(i, k) = 1]
f(n)=i=1∑n[gcd(i,k)=1]
很熟悉,因为它是每
k
k
k 个一循环,即
f
(
n
)
=
⌊
n
k
⌋
φ
(
k
)
+
f
(
n
m
o
d
k
)
f(n) = \left\lfloor\dfrac{n}{k}\right\rfloor \varphi(k) + f(n\bmod k)
f(n)=⌊kn⌋φ(k)+f(nmodk)
又因为
0
≤
n
m
o
d
k
<
k
0\le n\bmod k < k
0≤nmodk<k,所以可以
O
(
k
log
k
)
\Omicron(k\log k)
O(klogk) 暴力预处理
f
(
0
)
∼
f
(
k
)
f(0) \sim f(k)
f(0)∼f(k),
f
(
k
)
f(k)
f(k) 直接当
φ
(
k
)
\varphi(k)
φ(k) 用。
将
f
f
f 代回原式
a
n
s
=
∑
d
=
1
n
[
gcd
(
d
,
k
)
=
1
]
μ
(
d
)
⌊
n
d
⌋
f
(
⌊
m
d
⌋
)
ans = \sum_{d = 1}^n [\gcd(d, k) = 1] \mu(d) \left\lfloor\dfrac{n}{d}\right\rfloor f\left(\left\lfloor\dfrac{m}{d}\right\rfloor \right)
ans=d=1∑n[gcd(d,k)=1]μ(d)⌊dn⌋f(⌊dm⌋)
后面两项打包整除分块,
因为 n ≤ 1 0 9 n\le 10^9 n≤109,明显需要杜教筛。
前面两项的前缀和
g
(
n
)
=
∑
i
=
1
n
[
gcd
(
i
,
k
)
=
1
]
μ
(
i
)
g(n) = \sum_{i = 1}^n [\gcd(i, k) = 1] \mu(i)
g(n)=i=1∑n[gcd(i,k)=1]μ(i)
用类似杜教筛的思路
g
(
n
)
=
[
gcd
(
1
,
k
)
=
1
]
g
(
⌊
n
1
⌋
)
=
∑
i
=
1
n
[
gcd
(
i
,
k
)
=
1
]
g
(
⌊
n
i
⌋
)
−
∑
i
=
2
n
[
gcd
(
i
,
k
)
=
1
]
g
(
⌊
n
i
⌋
)
\begin{aligned} g(n) & = [\gcd(1, k) = 1] g\left(\left\lfloor\dfrac{n}{1}\right\rfloor \right) \\ & = \sum_{i = 1}^n [\gcd(i, k) = 1] g\left(\left\lfloor\dfrac{n}{i}\right\rfloor \right) - \sum_{i = 2}^n [\gcd(i, k) = 1] g\left(\left\lfloor\dfrac{n}{i}\right\rfloor \right) \end{aligned}
g(n)=[gcd(1,k)=1]g(⌊1n⌋)=i=1∑n[gcd(i,k)=1]g(⌊in⌋)−i=2∑n[gcd(i,k)=1]g(⌊in⌋)
而后面一项中的
[
gcd
(
i
,
k
)
=
1
]
[\gcd(i, k) = 1]
[gcd(i,k)=1] 的前缀和其实就是已经处理过的
f
f
f!
所以只要处理出前面那一项就可以完全仿照杜教筛递归 + 记忆化计算了。
∑
i
=
1
n
[
gcd
(
i
,
k
)
=
1
]
g
(
⌊
n
i
⌋
)
=
∑
i
=
1
n
[
gcd
(
i
,
k
)
=
1
]
∑
j
=
1
⌊
n
i
⌋
[
gcd
(
j
,
k
)
=
1
]
μ
(
j
)
=
∑
i
=
1
n
∑
j
=
1
⌊
n
i
⌋
[
gcd
(
i
j
,
k
)
=
1
]
μ
(
j
)
=
∑
T
=
1
n
[
gcd
(
T
,
k
)
=
1
]
∑
d
∣
T
μ
(
d
)
=
∑
T
=
1
n
[
gcd
(
T
,
k
)
=
1
]
(
μ
∗
1
)
(
T
)
=
∑
T
=
1
n
[
gcd
(
T
,
k
)
=
1
]
ε
(
T
)
=
1
\begin{aligned} \sum_{i = 1}^n [\gcd(i, k) = 1] g\left(\left\lfloor\dfrac{n}{i}\right\rfloor \right) & = \sum_{i = 1}^n [\gcd(i, k) = 1] \sum_{j = 1}^{\left\lfloor\frac{n}{i}\right\rfloor} [\gcd(j, k) = 1] \mu(j) \\ & = \sum_{i = 1}^n \sum_{j = 1}^{\left\lfloor\frac{n}{i}\right\rfloor} [\gcd(ij, k) = 1] \mu(j) \\ & = \sum_{T = 1}^n [\gcd(T, k) = 1] \sum_{d\mid T} \mu(d) \\ & = \sum_{T = 1}^n [\gcd(T, k) = 1] (\mu * \mathbf{1})(T) \\ & = \sum_{T = 1}^n [\gcd(T, k) = 1] \varepsilon(T) \\ & = 1 \end{aligned}
i=1∑n[gcd(i,k)=1]g(⌊in⌋)=i=1∑n[gcd(i,k)=1]j=1∑⌊in⌋[gcd(j,k)=1]μ(j)=i=1∑nj=1∑⌊in⌋[gcd(ij,k)=1]μ(j)=T=1∑n[gcd(T,k)=1]d∣T∑μ(d)=T=1∑n[gcd(T,k)=1](μ∗1)(T)=T=1∑n[gcd(T,k)=1]ε(T)=1
所以
g
(
n
)
=
1
−
∑
i
=
2
n
[
gcd
(
i
,
k
)
=
1
]
g
(
⌊
n
i
⌋
)
g(n) = 1 - \sum_{i = 2}^n [\gcd(i, k) = 1] g\left(\left\lfloor\dfrac{n}{i}\right\rfloor \right)
g(n)=1−i=2∑n[gcd(i,k)=1]g(⌊in⌋)
杜教筛即可做到
O
(
n
2
3
)
\Omicron(n^{\frac{2}{3}})
O(n32) 计算。
总时间复杂度为 O ( k log k + n 2 3 ) \Omicron(k\log k + n^{\frac{2}{3}}) O(klogk+n32)。
Tips : You should use long long
.
Warning : You cannot swap(n, m)
!!!
Code
//18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#include <unordered_map>
#define Debug(x) cout << #x << "=" << x << endl
#define int long long
using namespace std;
const int MAXN = 1e6 + 5;
const int N = 1e6;
const int MAXK = 2e3 + 5;
const int K = 2e3;
int k;
int p[MAXN], mu[MAXN], g[MAXN], f[MAXK];
bool vis[MAXN];
int GetF(int n)
{
return n / k * f[k] + f[n % k];
}
int gcd(int a, int b)
{
if (!b)
{
return a;
}
return gcd(b, a % b);
}
void pre()
{
for (int i = 1; i <= k; i++)
{
f[i] = f[i - 1] + (gcd(i, k) == 1);
}
mu[1] = g[1] = 1;
for (int i = 2; i <= N; i++)
{
if (!vis[i])
{
p[++p[0]] = i;
mu[i] = -1;
}
g[i] = g[i - 1] + (GetF(i) - GetF(i - 1)) * mu[i];
for (int j = 1; j <= p[0] && i * p[j] <= N; j++)
{
vis[i * p[j]] = true;
if (i % p[j] == 0)
{
mu[i * p[j]] = 0;
break;
}
mu[i * p[j]] = mu[i] * mu[p[j]];
}
}
}
int GetSumF(int l, int r)
{
return GetF(r) - GetF(l - 1);
}
unordered_map<int, int> dp;
int sublinear(int n)
{
if (n <= N)
{
return g[n];
}
if (dp.count(n))
{
return dp[n];
}
int res = 1;
for (int l = 2, r; l <= n; l = r + 1)
{
int k = n / l;
r = n / k;
res -= GetSumF(l, r) * sublinear(k);
}
return dp[n] = res;
}
int GetSumG(int l, int r)
{
return sublinear(r) - sublinear(l - 1);
}
int block(int n, int m)
{
int res = 0;
for (int l = 1, r; l <= n; l = r + 1)
{
int k1 = n / l, k2 = m / l;
if (!k2)
{
break;
}
r = min(n / k1, m / k2);
res += GetSumG(l, r) * k1 * GetF(k2);
}
return res;
}
signed main()
{
int n, m;
scanf("%lld%lld%lld", &n, &m, &k);
pre();
printf("%lld\n", block(n, m));
return 0;
}