题目描述
牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 �k 进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数 �n 和 �m,在 �k 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 ��yx 表示,其中 1≤�≤�,1≤�≤�1≤x≤n,1≤y≤m,且 �,�x,y 是整数。一个数是纯循环的,当且仅当其可以写成以下形式:
�.�1˙�2�3…��−1��˙a.c1˙c2c3…cp−1cp˙
其中,�a 是一个整数,�≥1p≥1;对于 1≤�≤�1≤i≤p,��ci 是 �k 进制下的一位数字。
例如,在十进制下,0.45454545……=0.4˙5˙0.45454545……=0.4˙5˙ 是纯循环的,它可以用 511115、10222210 等分数表示;在十进制下,0.1666666……=0.16˙0.1666666……=0.16˙ 则不是纯循环的,它可以用 1661 等分数表示。需要特别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 00 的循环或是 �−1k−1 的循环;而一个小数部分非 00 的有限小数不是纯循环的。
输入格式
只有一行,包含三个十进制数 �,�,�N,M,K 意义如题所述。
输出格式
一行一个整数,表示满足条件的美的数的个数。
输入输出样例
输入 #1复制
2 6 10
输出 #1复制
4
说明/提示
样例解释
满足条件的数分别是:
11=1.0000…11=1.0000…
13=0.3333…31=0.3333…
21=2.0000…12=2.0000…
23=0.6666…32=0.6666…
1111 和 2222 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1331 和 2662 也只计数一次。
数据范围
对于所有的测试点,保证 1≤�≤1091≤n≤109,1≤�≤1091≤m≤109,2≤�≤2×1032≤k≤2×103。
对于每个测试点,有以下约束(其中留空的表示没有特殊的约束):
测试点编号 | �n | �m | �k |
---|---|---|---|
11 | ≤10≤10 | ≤20≤20 | =2=2 |
22 | ≤100≤100 | ≤104≤104 | =2=2 |
33 | ≤103≤103 | =2=2 | |
44 | ≤104≤104 | =2=2 | |
55 | ≤10≤10 | ≤20≤20 | =3=3 |
66 | ≤100≤100 | ≤104≤104 | =3=3 |
77 | ≤103≤103 | =3=3 | |
88 | ≤104≤104 | =3=3 | |
99 | ≤10≤10 | ≤20≤20 | ≤100≤100 |
1010 | ≤100≤100 | ≤104≤104 | ≤100≤100 |
1111 | ≤103≤103 | ≤103≤103 | |
1212 | ≤104≤104 | ||
1313 | ≤105≤105 | ≤108≤108 | ≤100≤100 |
1414 | ≤2×105≤2×105 | ≤103≤103 | |
1515 | ≤5×105≤5×105 | ||
1616 | ≤106≤106 | ≤108≤108 | ≤100≤100 |
1717 | ≤2×106≤2×106 | ≤103≤103 | |
1818 | ≤5×106≤5×106 | ||
1919 | ≤107≤107 | ≤108≤108 | 100100 |
2020 | ≤2×107≤2×107 | ≤103≤103 | |
2121 | ≤2×107≤2×107 | ||
2222 | ≤108≤108 | ≤108≤108 | |
2323 | ≤108≤108 | ≤108≤108 | |
24,2524,25 |
提示
这部分将提供一个将分数化为对应的小数的方法,如果你已经熟悉这个方法,你不必阅读本提示。
分数可以通过除法,用分子除以分母化为对应的小数。有些分数在除法过程中无法除尽,这样的分数在不断进行的除法过程中余数一定会重复出现。从商数的个位所对应的余数起,设第一次重复出现的余数前两次出现的位置所对应的商数位分别是小数点后第 �a 位和小数点后第 �b 位(特殊地:如果其中一个对应的商数位是个位,则认为 �=0a=0;不妨设 �<�a<b),则其循环部分可以用小数点后第 �+1a+1 位到小数点后第 �b 位的循环来表示。
例如:在十进制下,将 511115 转化为小数时,个位开始的商数依次为 4,5,4,…4,5,4,…,对应的余数分别为 6,5,6,…6,5,6,…。余数第一次重复出现的位置是个位和小数点后第 22 位,那么 �=0,�=2a=0,b=2。
�=0,�=2a=0,b=2 即其循环部分可以用小数点第 11 位到第 33 位来表示。表示为:511=0.45454545…=0.4˙5˙115=0.45454545…=0.4˙5˙。
在十进制下,将 1661 转化为小数时,个位开始的商数依次为 1,6,6,…1,6,6,…,对应的余数分别为 4,4,4,…4,4,4,…。余数第一次重复出现的位置是小数点后第 11 位和小数点后第 22 位,即其循环部分可以用小数点后第 22 位来表示。表示为:16=0.1666……=0.16˙61=0.1666……=0.16˙。
需要注意的是:商数重复出现并不代表进入了循环节。
题解:
首先是判断分数��yx是否为纯循环小数的方法,
根据打表可以得到结论:
�K进制下,��yx为纯循环小数当且仅当�y与�k互质。
证明:
�K进制下,��yx为纯循环小数,则有
�∗��≡�(��� �)(�≠0)x∗kl≡x(mod y)(l=0)
两边同除�x.
��≡1(��� �)kl≡1(mod y)
得�,�k,y互质。
证毕。
题目转化为求
∑�=1�∑�=1�[���(�,�)==1][���(�,�)==1]x=1∑ny=1∑m[gcd(x,y)==1][gcd(y,k)==1]
∑�=1�∑�=1�[���(�,�)==1][���(�,�)==1]x=1∑ny=1∑m[gcd(y,k)==1][gcd(x,y)==1]
更换枚举顺序
∑�=1�[���(�,�)==1]∑�=1�[���(�,�)==1]y=1∑m[gcd(y,k)==1]x=1∑n[gcd(x,y)==1]
莫比乌斯反演得
∑�=1�[���(�,�)==1]∑�=1�∑�∣���(�,�)�(�)y=1∑m[gcd(y,k)==1]x=1∑nd∣gcd(x,y)∑μ(d)
枚举约数�d得
∑�=1��(�)∑�∣��∑�∣��[���(�,�)==1]d=1∑nμ(d)d∣x∑nd∣y∑m[gcd(y,k)==1]
∑�=1�[���(�,�)==1]�(�)∑�=1⌊��⌋∑�=1⌊��⌋[���(�,�)==1]d=1∑n[gcd(d,k)==1]μ(d)x=1∑⌊dn⌋y=1∑⌊dm⌋[gcd(y,k)==1]
∑�=1�[���(�,�)==1]�(�)⌊��⌋∑�=1⌊��⌋[���(�,�)==1]d=1∑n[gcd(d,k)==1]μ(d)⌊dn⌋y=1∑⌊dm⌋[gcd(y,k)==1]
令�(�)=∑�=1�[���(�,�)==1],�(�,�)=∑�=1�[���(�,�)==1]�(�)f(x)=i=1∑x[gcd(i,k)==1],s(x,k)=i=1∑x[gcd(i,k)==1]μ(i).
考虑求�(�)f(x),若�i与�k互质,则有�+�i+k与�k互质。
所以 �(�)=⌊��⌋�(�)+�(�f(x)=⌊kx⌋f(k)+f(x % �)k)
预处理�(�)f(x)满足1≤�≤�1≤x≤k的�(�)f(x),剩下的递归处理即可。
考虑求�(�,�)s(x,k).
�(�,�)=∑�=1�[���(�,�)==1]�(�)s(x,k)=i=1∑x[gcd(i,k)==1]μ(i)
=∑�=1��(�)[���(�,�)==1]=i=1∑xμ(i)[gcd(i,k)==1]
=∑�=1��(�)∑�∣���(�,�)�(�)=i=1∑xμ(i)d∣gcd(i,k)∑μ(d)
=∑�=1��(�)∑�∣�,�∣��(�)=i=1∑xμ(i)d∣i,d∣k∑μ(d)
=∑�∣��(�)∑�∣��(�)=d∣k∑μ(d)d∣i∑μ(i)
=∑�∣��(�)∑�=1⌊��⌋�(�∗�)=d∣k∑μ(d)i=1∑⌊dx⌋μ(i∗d)
若���(�,�)≠1gcd(i,d)=1时,�(�∗�)=0μ(i∗d)=0,对答案没有贡献.
由积性函数的性质�(��)=�(�)∗�(�)f(ab)=f(a)∗f(b)得
=∑�∣��(�)∑�=1⌊��⌋[���(�,�)==1]�(�)�(�)=d∣k∑μ(d)i=1∑⌊dx⌋[gcd(i,d)==1]μ(i)μ(d)
=∑�∣��(�)2∑�=1⌊��⌋[���(�,�)==1]�(�)=d∣k∑μ(d)2i=1∑⌊dx⌋[gcd(i,d)==1]μ(i)
=∑�∣��(�)2∑�=1⌊��⌋[���(�,�)==1]�(�)=d∣k∑μ(d)2i=1∑⌊dx⌋[gcd(i,d)==1]μ(i)
=∑�∣��(�)2∗�(⌊��⌋,�)=d∣k∑μ(d)2∗s(⌊dx⌋,d)
递归处理即可。
但当�=1k=1时,�(�,�)s(x,k)的值无法通过递归得出。
考虑�=1k=1的情况,
�(�,1)=∑�=1�[���(�,1)==1]�(�)s(x,1)=i=1∑x[gcd(i,1)==1]μ(i)
=∑�=1��(�)=i=1∑xμ(i)
由于1≤�≤1�81≤x≤1e8,杜教筛求前缀和即可。
题目中所求的
���=∑�=1�[���(�,�)==1]�(�)⌊��⌋∑�=1⌊��⌋[���(�,�)==1]ans=d=1∑n[gcd(d,k)==1]μ(d)⌊dn⌋y=1∑⌊dm⌋[gcd(y,k)==1]
整除分块处理。
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int read() {
int x = 0, f = 1; char ch;
while(! isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 3) + (x << 1) + (ch ^ 48));
return x * f;
}
map <pair <int, int>, int> mp;
int n, m, K, ans;
int tot, gcd_k[N], f[N], mu[N], Smu[N], vis[N], pri[N];
void init() {
for(int i = 1; i <= K; ++ i) gcd_k[i] = __gcd(i, K) == 1;
for(int i = 1; i <= K; ++ i) f[i] = f[i - 1] + gcd_k[i];
mu[1] = 1;
for(int i = 2; i < N; ++ i) {
if(! vis[i]) pri[++ tot] = i, mu[i] = -1;
for(int j = 1; j <= tot && i * pri[j] < N; ++ j) {
vis[i * pri[j]] = 1;
if(i % pri[j] == 0) break;
mu[i * pri[j]] = - mu[i];
}
}
for(int i = 1; i < N; ++ i) Smu[i] = Smu[i - 1] + mu[i];
}
int Sf(int x) {
return (x / K) * f[K] + f[x % K];
}
int Ss(int x, int k){
if((k == 1 && x <= N) || x == 0) return Smu[x];
if(mp[make_pair(x, k)]) return mp[make_pair(x, k)];
int res = 0;
if(k == 1) {
res = 1;
for(int i = 2, j; i <= x; i = j + 1) {
j = x / (x / i);
res -= (j - i + 1) * Ss(x / i, k);
}
}
else {
for(int i = 1; i * i <= k; ++ i) {
if(k % i) continue;
if(mu[i]) res += Ss(x / i, i);
if(i * i != k && mu[k / i]) {
res += Ss(x / (k / i), k / i);
}
}
}
return mp[make_pair(x, k)] = res;
}
signed main() {
n = read(); m = read(); K = read();
init();
for(int i = 1, j, nw = 0, lst = 0; i <= min(n, m); i = j + 1) {
j = min(n / (n / i), m / (m / i));
nw = Ss(j, K);
ans = ans + (nw - lst) * (n / i) * Sf(m / i);
lst = nw;
}
printf("%lld\n", ans);
return 0;
}