分数化小数
题目描述
对于一个分数(不一定是最简形式),给出它的小数形式,如果小数有循环节的话,把循环节放在一对圆括号中.
例如,1/4 =0.25
,1/3=0.3333
写成0.(3)
,1/7= 0.142857142857...
写成0.(142857)
。如果结果是一种整数xxx
,则用xxx.0
等表示整数xxx
。
输入包括一行,包括被空格分隔开的分子N和分母D(第一个是N,第二个是D)。
输出包括一行,为转换后的小数形式。
输入样例
45 56
输出样例
0.803(571428)
题目解释
题目中需要求一个 分数 的小数,如果是无限循环小数,则输出 0.xxx(xxx)
的格式。
因此我们考虑,先求出这个小数的 循环起始点(S) 和 循环长度(T)。
我们举个栗子。对于
x
=
45
56
x = \frac{45}{56}
x=5645 这种情况。
我们考虑先对
x
∗
10
x * 10
x∗10 即:
45
56
,
450
56
,
4500
56
,
45000
56
⋯
\frac{45}{56},\frac{450}{56},\frac{4500}{56},\frac{45000}{56}\cdots
5645,56450,564500,5645000⋯
然后我们将这些分数的分子进行
m
o
d
56
mod\ 56
mod 56 操作, 即:
45
56
,
2
56
,
20
56
,
32
56
,
40
56
,
8
56
,
24
56
,
16
56
,
48
56
,
32
56
,
40
56
⋯
\frac{45}{56},\frac{2}{56},\frac{20}{56},\frac{32}{56},\frac{40}{56},\frac{8}{56},\frac{24}{56},\frac{16}{56},\frac{48}{56},\frac{32}{56},\frac{40}{56}\cdots
5645,562,5620,5632,5640,568,5624,5616,5648,5632,5640⋯
我们可以明显的发现当操作进行到第 10 次的时候和第 4 次重复了,显然已经形成了一个长度为 6 的循环节,即从第 4 项开始循环。
由此我们可以推广到更一般的情况。假设分数为 p q \frac{p}{q} qp ,由于小数部分和整数无关,因此我们可以假设这个分数为真分数。不妨假设 p < q p<q p<q。
由上可知,我们可以把第
k
+
1
k + 1
k+1 个分数写成
p
∗
1
0
k
m
o
d
q
q
\frac{p*10^k\ mod\ q}{q}
qp∗10k mod q
因此我们可以假设第
i
i
i 个分数和第
j
j
j 个分数相等,即构成了一个循环节。有
p
∗
1
0
i
−
1
m
o
d
q
q
=
p
∗
1
0
j
−
1
m
o
d
q
q
\frac{p*10^{i-1}\ mod\ q}{q} = \frac{p*10^{j -1}\ mod\ q}{q}
qp∗10i−1 mod q=qp∗10j−1 mod q
两边同乘
10
10
10 ,得
p
∗
1
0
i
m
o
d
q
q
=
p
∗
1
0
j
m
o
d
q
q
\frac{p*10^i\ mod\ q}{q} = \frac{p*10^j\ mod\ q}{q}
qp∗10i mod q=qp∗10j mod q
即
p
∗
1
0
j
≡
p
∗
1
0
i
(
m
o
d
q
)
(
i
<
j
)
p * 10^j ≡ p * 10^i (mod \ q) \quad (i < j)
p∗10j≡p∗10i(mod q)(i<j)
又可表示为
p
∗
1
0
j
=
p
∗
1
0
i
+
q
∗
k
p*10^j = p*10^i + q*k
p∗10j=p∗10i+q∗k
令
g
=
g
c
d
(
p
,
q
)
g = gcd(p,q)
g=gcd(p,q),设
p
=
p
′
∗
g
,
q
=
q
′
∗
g
p = p'*g,q=q'*g
p=p′∗g,q=q′∗g。即
p
′
∗
1
0
j
−
p
′
∗
1
0
i
=
q
′
∗
k
p' *10^j - p'*10^i=q'*k
p′∗10j−p′∗10i=q′∗k
即
p
′
(
1
0
j
−
1
0
i
)
=
q
′
∗
k
→
p
′
∗
1
0
i
(
1
0
j
−
i
−
1
)
=
q
′
k
p'(10^j-10^i) = q'*k \ →\ p'*10^i(10^{j - i} - 1) = q'k
p′(10j−10i)=q′∗k → p′∗10i(10j−i−1)=q′k
由此可知
q
′
∣
1
0
i
(
1
0
j
−
i
−
1
)
p
′
q'|10^i(10^{j - i} - 1)p'
q′∣10i(10j−i−1)p′
因为
p
′
p'
p′ 和
q
′
q'
q′ 互质,因此可得
q
′
∣
1
0
i
(
1
0
j
−
i
−
1
)
q'|10^i(10^{j - i} - 1)
q′∣10i(10j−i−1)。
而
1
0
i
10^i
10i 为偶数,且和
q
′
q'
q′ 有公因数。
而
(
1
0
j
−
i
−
1
)
(10^{j - i} - 1)
(10j−i−1) 为奇数,显然不可能存在和
q
′
q'
q′ 的公因数,因此
q
′
q'
q′ 和
(
1
0
j
−
i
−
1
)
(10^{j - i} - 1)
(10j−i−1) 互质。
显然
i
i
i 由
1
0
i
10^i
10i 和
q
′
q'
q′ 共同决定,又知
1
0
i
10^i
10i 和
q
′
q'
q′ 的公因数由
2
2
2 和
5
5
5 贡献。
因此
i
=
m
a
x
(
n
,
m
)
i = max(n,m)
i=max(n,m),
n
n
n 为
q
′
q'
q′中贡献的
2
2
2 的个数,
m
m
m 为
q
′
q'
q′中贡献的
5
5
5 的个数。
接下来需要求循环节 T = j − i T = j - i T=j−i。
设
q
′
′
=
q
′
2
n
∗
5
m
q'' = \frac{q'}{2^n*5^m}
q′′=2n∗5mq′
经过一番计算,上式
q
′
∣
1
0
i
(
1
0
j
−
i
−
1
)
q'|10^i(10^{j - i} - 1)
q′∣10i(10j−i−1) 已经变成了
q
′
∣
2
n
5
m
(
1
0
j
−
i
−
1
)
∗
1
0
i
2
n
5
m
q'|2^n5^m(10^{j - i} - 1)*\frac{10^i}{2^n5^m}
q′∣2n5m(10j−i−1)∗2n5m10i
即
q
′
′
∣
(
1
0
j
−
i
−
1
)
∗
1
0
i
2
n
5
m
q''|(10^{j - i} - 1)*\frac{10^i}{2^n5^m}
q′′∣(10j−i−1)∗2n5m10i
又知
q
′
′
q''
q′′ 与
1
0
i
2
n
5
m
\frac{10^i}{2^n5^m}
2n5m10i 互质,且由上文可知
q
′
q'
q′ 和
(
1
0
j
−
i
−
1
)
(10^{j - i} - 1)
(10j−i−1) 互质可知
q
′
q'
q′ 和
(
1
0
j
−
i
−
1
)
(10^{j - i} - 1)
(10j−i−1) 也互质。
只需要解出
j
−
i
j -i
j−i 就是我们无限循环小数中的循环节了。即
1
0
j
−
i
≡
1
(
m
o
d
q
′
′
)
10^{j - i}≡1\ (mod\ q'')
10j−i≡1 (mod q′′)
不妨假设
x
=
j
−
i
x = j - i
x=j−i,即解
1
0
x
≡
1
(
m
o
d
q
′
′
)
10^x≡1\ (mod\ q'')
10x≡1 (mod q′′)
由欧拉定理可知,存在最小的
1
0
x
≡
1
(
m
o
d
q
′
′
)
10^x≡1\ (mod\ q'')
10x≡1 (mod q′′) ,当
x
x
x 是
φ
(
q
′
′
)
\varphi(q'')
φ(q′′) 的一个因子。
因此我们只需要去枚举所有
φ
(
q
′
′
)
\varphi(q'')
φ(q′′) 的因子,从而找到一个最小的
x
x
x,使得
1
0
x
≡
1
(
m
o
d
q
′
′
)
10^x≡1\ (mod\ q'')
10x≡1 (mod q′′)。
此时解出的
i
i
i 就是循环节开始的前一位,
x
x
x 即
j
−
i
j - i
j−i 为循环节的长度。
接下来的任务只需要模拟乘法,按照题目要求输出即可。
但是非常悲伤的事情是,队友暴力模拟 A 了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL p, q, S, T, Z;
LL Euler(LL x) {
LL ans = x;
for (LL i = 2; i * i <= x; i++) {
if (x % i == 0) {
ans = (ans/i) * (i - 1);
while (x % i == 0) x /= i;
}
}
if (x > 1) ans = (ans/x) * (x - 1);
return ans;
}
LL power(LL a, LL x, LL mod) {
LL ans = 1;
while (x) {
if (x & 1) ans = (ans * a)%mod;
a = (a * a)%mod;
x >>= 1;
}
return ans;
}
LL gcd(LL a, LL b) {
return b == 0? a:gcd(b, a%b);
}
LL get_first(LL &x) {
LL ans1 = 0, ans2 = 0;
while (x % 2 == 0) {
x /= 2;
ans1++;
}
while (x % 5 == 0) {
x /= 5;
ans2++;
}
return max(ans1, ans2);
}
LL get_T(LL x, LL mod) {
LL Min = 1e18;
for (LL i = 1; i * i <= x; i++) {
if (x % i == 0) {
if (power(10, i, mod) == 1) {Min = min(Min, i); break;}
if (power(10, x/i, mod) == 1) Min = min(Min, x/i);
}
}
return Min;
}
void print(LL p, LL q, LL S, LL T) {
printf("%lld.", p/q);
p -= q * (p/q);
for (int i = 0; i < S + T; i++) {
if (i == S) printf("(");
p *= 10;
printf("%lld", p/q);
p -= q * (p/q);
if (p == 0) break;
if (i == S + T - 1) printf(")");
}
printf("\n");
}
int main()
{
while (scanf("%lld %lld", &p, &q) != EOF) {
LL a = p, b = q;
LL g = gcd(p, q);
p /= g, q /= g;
S = get_first(q);
LL phi = Euler(q);
T = get_T(phi, q);
if (T == 1e18) S = T;
print(a, b, S, T);
}
return 0;
}