史密斯数java_2019.7.9 校内测试题 史密斯数

这篇博客介绍了如何寻找最接近且大于给定数的斯密斯数,这是一种特殊的数,其各位数字之和与其分解质因数后的质因数各位数字之和相等。文章提供了两种算法实现,一种是通过欧拉素数筛寻找质数,另一种是直接筛选合数,同时检查是否为斯密斯数。

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

【问题描述】:

美国有一位数字家名叫阿尔伯特·威兰斯基,他姐夫史密斯非常喜欢研究数学,所以两人经常在一起研讨各种数学问题。有时,两人碰不到一起,就习惯性地用电话交流。

两人刚结束电话交谈,史密斯突然灵感来临,对威兰斯基的电话号码“4937775”产生了兴趣,总觉得这是个特别的数。可它的特殊之处究竟在哪儿呢?史密斯开始思索考证起来,他先把 4937775 分解质因数:4937775=3×5×5×65837,然后再把 4937775 所有质因数各位上的数字相加得:3+5+5+6+5+8+3+7=42,接着他又把 4937775 各位上的数字相加得:4+9+3+7+7+7

+5=42,秘密终于找到了,原来这两个和相等。这真有意思,难道是巧合么?有没有其他的数也有此特点呢?结果发现,所有质数都是具有如此特点。

后来的数学家们把这样的数叫做“史密斯数”,而且还决定质数(简单不复杂)不属于斯密斯数。除质数之外还有许多数具有这样独特的性质,其中最小的数是 4。大家不妨检查一下,4=2×2,2+2=4。类似有,22=2×11,2+2=2+1+1;27=3×3×3,2+7=3+3+3。

你的任务是寻找最接近而且大于给定的数的斯密斯数。

【输入文件】:

只有一行一个整数 N,N 不超过 8 位数字。

【输出文件】:

一个整数,即第一个大于给定的数的斯密斯数。

【输入输出样例】:

smith.in

4937774

smith.out

4937775

【数据规模】:

考试得分:  0

主要算法 :  质数(欧拉素数筛)

应试策略:

可以明确的是,考试时题目都没有看懂,到底什么是斯密斯数(没有质数哦!),考试时将质数也看作斯密斯数了

错误中又将真正的斯密斯数打表打出,等了1500多秒,因为想要现将素数筛出,只需要O(n),能跑,但非质数“斯密斯数”*(史密斯数)就有点难跑了,所以打表(其实这就是foolish的想法,因为会爆掉代码50KB的限制,事实上是2.XXMB,)

将“斯密斯数”放入到一个数组中二分查找(真的有点stupid)

代码:

#include#include#include#include

#define FORa(i,s,e) for(int i=s;i<=e;i++)

#define FORs(i,s,e) for(int i=s;i>=e;i--)

#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,10000,stdin),pa==pb)?EOF:*pa++

#define File(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)

using namespacestd;static char buf[10000],*pa=buf,*pb=buf;

inlineintread();const int N=4000000,BN=278412;int n,cnt,prime[N+1],v[N+1];int a[BN+4]={4,22,27,58,85,94,121,166,202,}//后面的省略,不然上传不了啊!

mapmp;voidOulashai()

{

FORa(i,2,n)

{if(!v[i]) v[i]=i,prime[++cnt]=i,mp[i]=1;

FORa(j,1,cnt)

{if(prime[j]>v[i]||prime[j]*i>n) break;

v[prime[j]*i]=prime[j];

}

}

}int Back(intx)

{int cnt=0;while(x) cnt=cnt+x%10,x/=10;returncnt;

}bool Check(intx)

{int fx=x,cnt1=0,cnt2=Back(x);

FORa(i,2,sqrt(fx))

{int ct=0,backi=Back(i);if(fx%i==0)

{while(fx%i==0)

{

fx/=i,ct++;if(cnt1+ct*backi>cnt2) return 0;

}

cnt1=cnt1+ct*backi;

}

}if(fx>1) cnt1+=Back(fx);return cnt1==cnt2;

}intmain()

{

File("smith");

n=read(),Oulashai();/*FORa(i,1000000,n)

{

if(!mp[i])

if(Check(i))

printf("%d,",i);

}*/FORa(i,0,BN+2) mp[a[i]]=1;

FORa(i,n+1,N+20)

{if(mp[i])

{

printf("%d",i);

exit(0);

}

}return 0;

}

inlineintread()

{

registerint x(0);register int f(1);register charc(gc);while(c'9') f=c=='-'?-1:1,c=gc;while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;return x*f;

}

非完美算法:

请看正解

正解:

已知大于N的最大的斯密斯数为N的最大值的基础上加上2000左右(打表小函数得出),筛选1到最大斯密斯数之间的质数,时间复杂度的为O(1e9),勉强能过,空间复杂度为bool[1e9],又因为这个区间质数最多为5762455(小函数提前计算),则再加上int[5762455],勉强还有点空间

从n+1开始寻找合数且为"史密斯数",即为斯密斯数.

代码

#include#include#include

#define FORa(i,s,e) for(int i=s;i<=e;i++)

#define FORs(i,s,e) for(int i=s;i>=e;i--)

#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,10000,stdin),pa==pb)?EOF:*pa++

#define File(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)

using namespacestd;static char buf[10000],*pa=buf,*pb=buf;

inlineintread();const int N1=100000000,N2=5762455;int n,cnt,prime[N2+1];bool bz[N1+1];void Oulashai(intfn)

{

FORa(i,2,fn)

{if(!bz[i]) prime[++cnt]=i;

FORa(j,1,cnt)

{if(i*prime[j]>fn) break;

bz[i*prime[j]]=true;if(i%prime[j]==0) break;

}

}

}int Back(intx)

{int ct=0;while(x) ct=ct+x%10,x/=10;returnct;

}bool Check(intx)

{int fx=x,cnt1=0,cnt2=Back(x);

FORa(i,2,sqrt(fx))

{int ct=0,backi=Back(i);if(fx%i==0)

{while(fx%i==0)

{

fx/=i,ct++;if(cnt1+ct*backi>cnt2) return 0;

}

cnt1=cnt1+ct*backi;

}

}if(fx>1) cnt1+=Back(fx);return cnt1==cnt2;

}intmain()

{

File("smith");

n=read(),Oulashai(n+2000);int p=n;while(1)

{++p;if(bz[p]&&Check(p))

{

printf("%d",p);

exit(0);

}

}return 0;

}

inlineintread()

{

registerint x(0);register int f(1);register charc(gc);while(c'9') f=c=='-'?-1:1,c=gc;while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;return x*f;

}

总结:

Handsome guy and beaty,读题真的very important!

学会正确分析时空复杂度1B=1字节哦!

e8d8dbfb2bfda65ce78cc5dc86c41b48.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值