P1587 [NOI2016] 循环之美

该问题讨论了如何确定在给定进制下,有多少个纯循环小数可以用特定形式的分数表示。通过莫比乌斯反演和数学推理,可以计算出这些美的数的个数。题目提供了详细的转换方法和样例解释,并给出了数据范围和测试点的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 �k 进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数 �n 和 �m,在 �k 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 ��yx​ 表示,其中 1≤�≤�,1≤�≤�1≤x≤n,1≤y≤m,且 �,�x,y 是整数。一个数是纯循环的,当且仅当其可以写成以下形式:

�.�1˙�2�3…��−1��˙a.c1​˙​c2​c3​…cp−1​cp​˙​

其中,�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≤108100100
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∑n​y=1∑m​[gcd(x,y)==1][gcd(y,k)==1]

∑�=1�∑�=1�[���(�,�)==1][���(�,�)==1]x=1∑n​y=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∑n​d∣gcd(x,y)∑​μ(d)

枚举约数�d得

∑�=1��(�)∑�∣��∑�∣��[���(�,�)==1]d=1∑n​μ(d)d∣x∑n​d∣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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值