UVA 202 有理数化为循环小数求循环节 UVA 11809 对数处理数据

本文解析了UVA202和UVA11809两道编程挑战题目,介绍了如何利用抽屉原理求解循环小数的循环节,并探讨了通过精确计算和对数转换解决数值范围过大的问题。

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

                  UVA 202  

                            题目的大致意思是给出有理数的分子和分母,要你找到化为循环小数后的循环节。

                            在此仅仅讨论有循环节非0的情况

                            给定分子a,分母b,假若没想到最多需要做除法的次数,可以用vector之类的玩意。

                            以下是我没有想到的地方:

                            原理:抽屉原理

                            a被b除,余数一共有b种可能(0 ~ b-1),当我在做第b+1次除法的时候,在这b+1个余数中一定会至少有重复的一对。

    我的做法是把每一次的商和余数作为一个结构体来储存,开了一个3010的数组,每一次计算后和之前数组里面的相比较

                            感觉用到抽屉原理很不错,以前没有这样想过。

                             自己的代码感觉仍然有些繁琐


                            

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

struct Node{
	int quotient, remain;
	bool friend operator==(const Node& a, const Node& b){
		return a.quotient == b.quotient&&a.remain == b.remain;
	}
}ans[3010];

int ans_length;

int main(){
	ios_base::sync_with_stdio(false);
	int n, m, num, k; bool flag = false;
	Node test, *pn = nullptr;
	while (cin >> n >> m){
		num = n / m, k = n%m;
		if (k == 0)
			flag = true;
		else{
			while (k != 0){
				k *= 10, test.quotient = k / m, test.remain = k%m, k %= m;
				pn = find(ans, ans + ans_length, test);
				if (ans + ans_length != pn)
					break;
				else
					ans[ans_length++] = test;
			}
		}
		cout << n << '/' << m << " = " << num << ".";
		if (k == 0){
			for (int i = 0; i < ans_length - 1; ++i)
				cout << ans[i].quotient;
			if (!flag)
				cout << test.quotient;
			cout<< "(0)\n   1 = number of digits in repeating cycle\n";
		}
		else{
			if (ans_length>50){
				for (int i = 0; ans + i != pn; ++i)
					cout << ans[i].quotient;
				cout << "(";
				for (Node* pi = pn; pi-ans<50; ++pi)
					cout << pi->quotient;
				cout << "...)\n   " << ans + ans_length - pn << " = number of digits in repeating cycle\n";
			}
			else{
				for (int i = 0; ans + i != pn; ++i)
					cout << ans[i].quotient;
				cout << "(";
				for (Node* pi = pn; pi != ans + ans_length; ++pi)
					cout << pi->quotient;
				cout << ")\n   " << ans + ans_length - pn << " = number of digits in repeating cycle\n";
			}
		}
		cout << endl;
		ans_length = 0; flag = false;
	}
	return 0;
}



               UVA 11809    

考虑到数据的范围,A∈(0,10),M∈(0,10),E ∈[1,30],数据量并不是很大,很自然的考虑打表,然后在表中查询,关键是怎么生成表的问题。

0.1111111(M+1个)* 2^(2^E-1)  =   A*10^B

 这个公式是我最开始想到的打表的依据,可是后来发现E最大可以到30,double是存不下的。

以下是我没有想到的地方

  两边可以取对数,因为在计算左边的时候,M和E是我们穷举的,因此左边的值是已知的,不妨另左边的值为k

lgk = lg A + B 

变成这样的式子,只需要通过强制转换提取整数部分算出B,然后相减提取小数部分就算出A 了

以下是代码

#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

const double lg2 = log10(2), accuracy = 1e-5;
double mantissa[10][31];
long long num[10][31];
char con[100];

int main(){
	double a, b, c;
	long long d;
	for (int i = 0; i < 10;++i)
	for (int j = 1; j <= 30; ++j){
		a = log10(1 - pow(0.5, i + 1)), b = lg2*((1 << j) - 1), c = a + b;
		num[i][j] = (long long)c, mantissa[i][j] = pow(10, c - num[i][j]);
	}
	while (scanf("%s", con)){
		if (strlen(con) == 3)
			break;
		con[17] = ' ';
		sscanf(con, "%lf%lld", &a, &d);
		for (int i = 0; i < 10; ++i)
		for (int j = 1; j <= 30; ++j)
		if (num[i][j] == d && ((fabs(a - mantissa[i][j]) < accuracy) || (fabs(a / 10 - mantissa[i][j]) < accuracy)))
			printf("%d %d\n", i, j), j = 31, i = 10;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值