PTA 7-178 吸血鬼素数
分数 10
作者 林生佑
单位 浙江传媒学院
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
代码长度限制
16 KB
C (gcc)
时间限制
400 ms
内存限制
64 MB
其他编译器
时间限制
400 ms
内存限制
64 MB
#include <stdio.h>
#include <math.h>
int prime(int flag, int x){ //判断是否为素数
if(x == 1)
flag = 1; //返回不是素数
else if(x == 2)
flag = 0; //返回是素数
else{
for(int i = 2; i < x; i++){
if(x % i == 0){
flag = 1;
break;
}else
flag = 0;
}
}
return flag;
}
int digit(int x){ //求n的位数
int count; //记录位数
for(count = 1; ; count++){
x /= 10;
if(x == 0)
return count;
}
}
int main(){
int n, m; //两个尖牙数
int nm[10], vamp[10]; //用数组统计各数字出现的次数
int counts = 0; //标记各数字出现的次数,默认相等
int flag = 0, decimals; //标记素数flag,默认是素数; n的位数decimals
int origin; //吸血鬼数的位数
int vampNumb; //吸血鬼数
scanf("%d", &n); //输入第一个尖牙数
int x; //函数参数
if(n > 0 && n < 1000){
x = n;
flag = prime(flag, x); //判断第一个尖牙n是否是素数
if(flag == 1){ //若不是素数,则一定不是吸血鬼素数
printf("NO");
return 0;
}else if(flag == 0){ //是素数
decimals = digit(x); //求n的位数
origin = 2 * decimals; //吸血鬼数的位数
}
for(int j = pow(10, origin - 1); j < pow(10, origin); j++){ //寻找第二个尖牙数
if(j % n == 0){
m = j / n;
x = m;
vampNumb = j;
flag = prime(flag, x);
if(flag == 0 && digit(x) == decimals && n % 10 != 0 && m % 10 != 0){
//如果第二个尖牙数是素数;第二个尖牙数的位数等于第一个尖牙数的位数;两个尖牙数的个位不能同时为0
for(int i = 0; i <= 9; i++){ //遍历数组
nm[i] = 0; //初始化
vamp[i] = 0;
}
int a = m, b = n, c = vampNumb;
while(a > 0){ //处理m,统计其中各个数字的出现次数
nm[a % 10]++;
a /= 10;
}
while(b > 0){ //处理n,统计其中各个数字的出现次数
nm[b % 10]++;
b /= 10;
}
while(c > 0){ //处理vampNumb,统计其中各个数字的出现次数
vamp[c % 10]++;
c /= 10;
}
counts = 0;
for(int k = 0; k <= 9; k++){
if(nm[k] != vamp[k]){ //若数字次数有一次数出现不相等
counts = 1;
break;
}
}
if(counts == 0){
printf("YES");
return 0;
}
}
}
}
if(flag == 1){
printf("NO");
}
}
return 0;
}
解题思路:
设:vampNumb = n * m ,vampNumb 是吸血鬼数,n 是输入的第一个尖牙数
step1:先判断 n 是不是素数,如果不是素数就不可能是吸血鬼素数,直接输出"NO",结束程序。
step2:如果是素数,则算出 n 的位数 decimals;
step3:根据 decimals 得出吸血鬼数 vampNumb 的位数为 2 * decimals
step4:寻找另一个尖牙数 m,当且仅当 vampNumb % n == 0。求出的 m 也应该是吸血鬼素数,所以还要判断 m 的位数是否也是 decimals 位数,m 是否也是素数。
step5:因为吸血鬼数 vampNumb 等于自己各个数字任意组成的两个 n 位数的乘积,所以 vampNumb 各个数字出现的次数等于 n 和 m 各个数字出现的次数之和。
step6:可以建立两个数组(变量名称是个人习惯) int nm[10],vamp[10];全部元素初始化为0,分别用来记录 vampNumb 各个数字出现的次数和 n 和 m 各个数字出现的次数之和,如果完全相同,就说明 n 和 m 是吸血鬼素数。
step7:如果 vampNumb 一直到范围上限都没找到对应的 m,则 n 不是吸血鬼素数。
归属知识点:
函数
数组
选择结构
循环结构