一道比较简单的题目,题目意思比较明确,没必要多解释。但是我读题的时候还是着急了点,中间的一段直接忽略的,导致没有看到素数的影响,浪费了不少时间。
寻找Smith Number基本上就是寻找素数的方法,使用试除法,比较简单。也就是用素数不断的除啊除,除到差不多了就可以搞定了。题目的主要难点在于时间,有可能会超时。做题前建议先看看status,这样可以发现TLE的比较多,一般这道题目就是需要做好时间优化。好了贴下代码,结合代码说说我的解法。
#include<iostream> #include<map> #include<stdio.h> #include<math.h> using namespace std; int prime1[10002]; int prime[10002]; int M[10002]; long tagend; int get_sum(long x) { int sum =0; while(x) { sum+=x%10; x/=10; } return sum; } void init_prime(int *p, int *m) { p[0] = 0; p[1] = 0; p[2] = 1; m[0] = 0; m[1] = 0; m[2] = 2; int tag = 0; prime[tag++] = 2; for(int i=3;i<=10001;i++) { p[i] = 1; m[i] = get_sum(i); for(int j=2;j<=sqrt(i);j++) { if(i%j == 0) { p[i] = 0; m[i] = m[j] + m[i/j]; break; } } if(p[i]) { prime[tag++] = i; } } tagend = tag; } bool isSmith(long num) { if(num <= 10001) { return (get_sum(num) == M[num])&&!prime1[num]; } int sum = 0; long tmp = num; int count = 0; for(int i=1;i<tagend;i++) { while(num%prime[i] == 0 && num>10001) { sum += M[prime[i]]; num/=prime[i]; } if(num == 1) { break; }else if(num <=10001) { break; } } if(num == tmp) return false; if(num >10001) { return get_sum(tmp) == sum+get_sum(num); } return get_sum(tmp) == sum+M[num]; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "rt", stdin); freopen("output.txt", "wt", stdout); #endif init_prime(prime1, M); long num; scanf("%ld",&num); while(num) { for(long i= num+1;;i++) { if(isSmith(i)) { printf("%ld/n", i); break; } } scanf("%ld",&num); } }
代码有点搓,看起来不是很顺眼。不过诸位看懂应该没什么问题的。
首先我的想法是输入的数值最大就是99999999,而试除法上限是sqrt(n),所以大概10001就够了。我首先计算了小于10002的所有数字的素数性质和Smith值。然后对于要判断的数字,如果小于10002就直接判断,如果大于就进行试除,这里可以采用很多的循环方式,比如:for i =2 to 10001, for i=10001 to 2, for i=prime[0] to prime[tagend], for i=prime[tagend] to prime[0]。通过尝试,发现上面代码中的方式是最快的,当然其他方式都能AC。
好了,其他也没什么好说的,写的时候小心点就好了,我还是WA了n次才搞定的,不够谨慎啊不够谨慎。