寻找雷劈数(C实现)

雷劈数,定义为:若正整数X(在n进位下)的平方可以分割为二个数字,而这二个数字相加后恰等于X,那么X的平方就是(n进位下的)一个雷劈数,又称卡布列克数。例如55^2=3025,而30+25=55,那么3025就是一个雷劈数。

最小的雷劈数:81

问题:找到1000000以内的所有雷劈数

思路:雷劈数开方出来必然是整数,因此i从9开始(因为最小的为81,sqrt(81)=9),一直到sqrt(1000000)=1000,这样可以减少循环次数。每一次循环,先确定i^2的位数,记为count,再分别按顺序将高位和低位分别赋给left和right,最后根据雷劈数定义进行判断。

代码

#include<stdio.h>
#include<math.h>

int main() {
	int i, x, count = 0;
	int left, right;
	printf("10到1000000之内的雷劈数有:\n");
	for (i = 3; i < 1000; i++) {
		x = i * i;
		while (x) {
			x = x / 10;
			count++;
		}
		x = i * i;
		for (int j = 1; j < count; j++) {
			left = x % ((int)pow(10, j));
			right = x / ((int)pow(10, j)); //关键步骤
			if (left + right == i) {
				printf("%d\n", x);
				break;
			}
		}
	}
	return 0;
}

建议使用vs运行,我用cb运行时结果出错,可能是编译器版本问题
vs 2017运行结果
在这里插入图片描述

雷劈是指一个如果是合,而且它的因子中含有“雷劈因子”(即7),则称这个为“雷劈”。根据定义,我们可以得到一个暴力的算法:枚举每个,然后判断它是否是合,再判断它的因子中是否包含7。但这个算法显然是不可取的,因为它的时间复杂度是 $O(n\sqrt{n})$,无法通过本题的大据测试。 实际上,我们可以根据“雷劈因子”的性质,设计一种更高效的算法。我们可以先枚举所有包含“雷劈因子”的字,然后对它们的倍进行标记,标记完成后,没有被标记的就是“雷劈”。 具体实现的过程是: 1.首先标记7的倍,即将它们的值全部置为1,表示它们不是“雷劈”。 2.然后标记其他包含“雷劈因子”的字的倍,比如 14、17、21、27、28、35 等等。这些字可以表示成 $7k+r$ 的形式,其中 $r$ 是 $1,2,4$ 中的一个。我们枚举 $r$,然后计算 $k$ 的取值范围,对于每个 $k$,将 $7k+r$ 倍的值置为1,表示它们不是“雷劈”。 3.最后,没有被标记的就是“雷劈”。 下面是一个实现: ```c #include <stdio.h> #include <string.h> #define MAX_N 1000000 char is_not_prime[MAX_N + 1]; int main() { memset(is_not_prime, 0, sizeof is_not_prime); is_not_prime[0] = is_not_prime[1] = 1; for (int i = 2; i <= MAX_N; i++) { if (!is_not_prime[i]) { if (i % 7 == 0) { // 7 的倍不是雷劈 is_not_prime[i] = 1; } else { for (int j = 1; j <= 3; j++) { // 遍历 r = 1, 2, 4 int x = i * 7 + j; if (x <= MAX_N) { // 防止越界 is_not_prime[x] = 1; } } } } } for (int i = 1; i <= MAX_N; i++) { if (!is_not_prime[i]) { printf("%d\n", i); } } return 0; } ``` 这里使用一个布尔组 `is_not_prime` 来标记每个是否是“雷劈”。组初始化为0,表示每个都不是“雷劈”。然后按照前面的算法,对于包含“雷劈因子”的字,将它们的倍标记为1,表示它们不是“雷劈”。最后,遍历组,输出没有被标记的,即为“雷劈”。 由于最大目可能达到1000000,我们需要使用一个布尔组来标记每个,以节省空间。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值