吸血鬼素数 C/C++

吸血鬼素数

1994年,美国数学家皮科夫在一篇文章中首次提出了吸血鬼数。如果一个2n(n是自然数)位的自然数等于自己各个数字任意组成的两个n位数的乘积,那么这个自然数就叫吸血鬼数。其中这两个n位数都被称为獠牙或尖牙。比如1260=21×60,所以1260是一个吸血鬼数。注意两个尖牙的个位数不能同时为0,例如虽然126000=210×600,但126000却不是吸血鬼数。在此基础上,2002年,数学家里维拉定义了吸血鬼素数。如果吸血鬼数的两个尖牙都是素数,则这两个尖牙都叫吸血鬼素数。例如,117067=167×701,而167和701都是素数,所以167和701都是3位吸血鬼素数。

输入一个正整数n(小于1000),请判断它是否吸血鬼素数。如果是,打印YES,否则打印NO。

输入格式:

一个小于1000的正整数n

输出格式:

YES或者NO

输入样例:

701

输出样例:

YES

思路:

训练的时候遇到了这题,因为这题的输出只有"YES"和"NO",我直接无脑输出"YES"骗了一点分。‍_(:з」∠)_‍

正常的解法是:
设:i = n*m ,i是吸血鬼数,n是输入的数

先判断n是不是素数,如果不是素数就不可能是吸血鬼素数,直接输出"NO",结束程序。

如果是素数,则算出n的位数h,根据h得出吸血鬼数i的位数为2h,范围为102h-1 <= i < 102h,如:n = 701,h = 3,2h = 6,105 <= i < 106,100000 <= i < 1000000。

求出m当且仅当i%n == 0。求出的m也应该是吸血鬼素数,所以还要判断m的位数是否也是h,m是否也是素数。

因为吸血鬼数i等于自己各个数字任意组成的两个n位数的乘积,所以i各个数字出现的次数等于n和m各个数字出现的次数之和。
可以建立两个数组(变量名称是个人习惯)int is[10],nm[10];全部元素初始化为0,分别用来记录i各个数字出现的次数和n和m各个数字出现的次数之和,如果完全相同,就说明n和m是吸血鬼素数。

如果i一直到102h都没找到对应的m,则n不是吸血鬼素数。

代码

#include<bits/stdc++.h>
using namespace std;

int ss(int x); //判断是不是素数 
int weishu(int x); //计算有多少位 

int main(void)
{
	int n,m;
	int nm[10],is[10];
	int h,max_h;
	int i,j;
	int z;
	
	scanf("%d",&n);
	if(ss(n) == 1){
		h = weishu(n);
		max_h = (int)pow(10,2*h);
//		printf("h = %d\n",h);
//		printf("i = %d\n",(int)pow(10,2*h-1));
//		printf("max_h = %d\n",max_h);
		for(i = (int)pow(10,2*h-1);i < max_h;i++){
			if(i%n == 0){
				m = i/n;
				if(weishu(m) == h && ss(m) == 1){ //位数相同,都是素数 
					//printf("%d %d %d\n",i,n,m);
					for(j = 0;j < 10;j++){
						nm[j] = 0;
						is[j] = 0;
					}
					while(m > 0){
						nm[m%10]++;
						m /= 10;
					}
					m = n;
					while(m > 0){
						nm[m%10]++;
						m /= 10;
					}
					m = i;
					while(m > 0){
						is[m%10]++;
						m /= 10;
					}
					z = 1;
					for(j = 0;j < 10;j++){
						if(nm[j] != is[j]){
							z = 0;
							break;
						}
					}
					if(z == 1){
						printf("YES");
						break;
					}
				}
			}
		}
		if(z == 0){
			printf("NO");
		}
	}else {
		printf("NO");
	}
	
	return 0;
}

int ss(int x){
	int z = 1;
	int i;
	
	if(x == 2){
		z = 1;
	}else if(x > 2){
		if(x%2 == 0){
			z = 0;
		}
		for(i = 3;i <= sqrt(x) && z == 1;i += 2){
			if(x%i == 0){
				z = 0;
				break;
			}
		}
	}else {
		z = 0;
	}
	
	return z;
}

int weishu(int x){
	int z = 0;
	
	if(x != 0){
		while(x != 0){
			z++;
			x /= 10;
		}
	}else {
		z = 1;
	}
	
	return z;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值