题意:如果一个数n,把它各个位上的数加起来的和等于它素因子分解以后每个数的每个位上的和,并且这个数不是素数,那么这个数就是史密斯数。求大于n的最小的史密斯数。
思路:打素数表加快点速度,因为数最大为10^8,所以打表打到10000以内的素数就行了。
错误:最开始想着先判断素数,然后先用了miller-rabin测试……后来发现完全用不着。把大于n看成了大于等于n。
代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<ctime>
#include<cstdlib>
using namespace std;
bool valid[10005];
int ans[10000];
int tot=0;
void getprime()
{
memset(valid,true,sizeof(valid));
valid[1]=valid[0]=false;
int n=10001;
for(int i=2;i<=n;++i){
if(valid[i]){
ans[tot++]=i;
}
for(int j=0;((j<tot)&&(i*ans[j]<=n));j++){
valid[i*ans[j]]=false;
if(i%ans[j]==0)break;
}
}
}
int ss(int n){
int ret=0;
while(n){
ret=ret+n%10;
n/=10;
}
return ret;
}
int factor(int n){
int i=0;
int ret=0;
int tmp;
int rec=n;
while(n!=1)
{
if(n%ans[i]==0)
{
tmp=ss(ans[i]);
}
while(!(n%ans[i])){
n/=ans[i];
ret+=tmp;
}
i++;
if(i>=tot)break;
}
if(ans[i-1]==rec)return -1;
if(n!=1)
{
if(ret!=0)
ret+=ss(n);
}
return ret;
}
int main(){
// freopen("data.txt","r",stdin);
getprime();
int n;
while(scanf("%d",&n) && n>0)
{
n++;
while(1)
{
int sum1=ss(n);
int sum2=factor(n);
if(sum1==sum2)break;
n++;
}
printf("%d\n",n);
}
return 0;
}