转化小数题解

题目:给定一个以十进制表示的分数 a/b,保证 a<b,请将它化成一个二进制的小数。若存在循环节,用圆括号表示循环节。

举个栗子:

in:1 4                                        out:0.01

in:1.5                                        out:0.(0011)

还记得十进制转二进制小数部分怎么转吗?对乘二正取整。

就比如举个栗子:0.475      (懂就行,可省略)

第一步:0.475

            x       2    

              0.95----------------------->0

              

                0.95

            x       2        

             1.9------------------------->1

             0.9

            x   2    

            1.8------------------------>1

        

            0.8

            x   2    

           1.6------------------------->1

            0.6

            x   2    

            1.2------------------------->1

            0.2

            x   2    

           0.4------------------------>0

           0.4

            x   2    

           0.8----------------------->0

           0.8

            x   2    

             1.6----------------->1

             0.6。。。。。。。。。

发现没有,0.6在之前出现过了,所以在上次出现的位置开始到1.6的1结束就是循环节,即

0.01111001

但如果像1/3这种十进制就是循环小数怎么办?对,用分数表示

Solution:

每次那个剩余的数

n,m

每次观察有没有一样的(可以用map做,不建议用double,用PII(pair<int,int>)较好)

每次n*=2

如果n>m则n-=m,答案为1

如果n=m则答案为1,直接结束暴力

如果n<m则答案为0

必须要存储答案,用map记录{n,m}时所对应第几次操作,这样可以快速找到括号位置

其他没什么问题,上代码!

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
int n, m, ct, pos = -1;
map<pair<int, int>, int> mp;
//mp[{n,m}]表示n/m在第几次操作,为0表示没有出现过
bool ans[N];//记录答案
void tog(int &n, int &m) {
//全名to-gcd,作用是约分
	int t = __gcd(n, m);
	n /= t, m /= t;
}
signed main() {
	cin >> n >> m;
	cout << "0.";//因为n<m,所以0打头
	while (1) {
		tog(n, m);//先约分,很重要
//如果不约分,1/2和2/4就算两种情况
		if (mp[ {n, m}]) {//如果有过
			pos = mp[ {n, m}];//记录位置
			break;
		}
		mp[ {n, m}] = ++ct;//记录
		n *= 2;//乘二正取整
		if (n > m) n -= m, ans[ct] = 1;//n/m>1是
		else if (n == m) {//n/m=1时
			ans[ct] = 1;
			break;
		} else ans[ct] = 0;//n/m<1时
	}
	for (int i = 1; i <= ct; ++i) {
		if (pos == i) cout << '(';//如果到位置输出'('
		cout << ans[i];
	}
	if (pos > 0) cout << ')';//是否要输出')'
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值