Programming Challenges 习题5.9.4

探讨如何解决PC/UVa 110504/10127题目的枚举算法,通过避免整数溢出和优化运行时间,实现对全1数的高效整除检查。

PC/UVa:110504/10127

Ones

这一章因为是高精度算术,所以我总是担心整数溢出,以及超时。

这道题目就是枚举,看最短多长的全1的数可以整除输入n,根据uDebug上的测试用例,长度可以达到几千多,所以内置类型肯定是溢出了。

其实题目中已经给了提示了,找一个x,使得a * b = p,其中p = 10^0 + 10^1 + …… + 10^(x-1)a就是n,既然没让找b,那也就是p % a = 0,而p又可以拆分为若干个数字的和,所以可以利用%运算的性质,和的模等于每一项的模的和再取模。

在当前x不满足输出的情况下,需要将x1,对应的p就变大了10 ^ (x - 1),然后可以把次数拆分成较小的,也就是利用另一个性质,积的模等于每一项的积再取模,为了避免溢出,每当积大于模数时,就可以取一次模。

代码中x表示总位数,i就是x - 1,表示这一次新增加部分的次数,viOnes是可以用内置类型表示的10的幂模n的值,用来将10 ^ i拆成较小的数。内层while循环使用的是第二个性质,外层while循环(r += tmp)是第一个性质。

根据UVa上的提交结果,适当增大viOnes可以加快运行时间。第一次提交时viOnes只计算到比n大的10的幂,时间0.180,第二次提交时viOnes计算到10^9,时间0.090。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	unsigned int n = 0;
	while (cin >> n){
		vector<unsigned int> viOnes;
		for (size_t i = 1; i < 1000000000; i *= 10)
		{
			viOnes.push_back(i % n);
		}
		size_t x = 1, r = 1 % n;
		while (r != 0){
			x++;
			size_t i = x - 1, tmp = 1;
			while (i >= viOnes.size()){
				tmp *= viOnes.back();
				if (tmp >= n) tmp %= n;
				i -= (viOnes.size() - 1);
			}
			tmp *= viOnes[i];
			r += tmp;
			if (r >= n) r %= n;
		}
		cout << x << endl;
	}
	return 0;
}
/*
3
7
9901
*/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值