Sum of Consecutive Prime Numbers
题目描述
numbers, so neither 7 + 13 nor 3 + 5 + 5 + 7 is a valid representation for the integer 20.
Your mission is to write a program that reports the number of representations for the given positive integer.
2 3 17 41 20 666 12 53 0Sample Output
1 1 2 3 0 0 1 2
题目的意思是,给一个数,是不是连续几个素数的和,求出所有情况的个数。
如果没看到 consecutive,还以为要深搜,不过数字这么大,深搜是不可能的。
既然是连续的,就可以直接枚举所有的素数。
数据范围 10000 以内,所以可以先打表,标记 10000 以内的数字是否是素数。
对一个给定的 n , 可以用一个数组 package 储存 n 范围以内的素数,然后开始枚举。
当前枚举的数 > n/2 时,就可以先跳出循环,因为至少两个大于 n/2 的数字加
起来肯定比 n 大。
不过在这之前 , ans 记录情况个数,初始化是 ans == is[n] , 因为如果 n 是素数,
n = n 也是满足的,这也是一种情况。
也回顾一下素数的判断,一个正数的因子只有 1 和它本身。
int is_prime( int n ){
if( n < 2 || ( n != 2 && n % 2 == 0 ) )
return 0 ;
int i = 3 ;
for( i = 3 ; i <= sqrt( n ) ; i += 2 )
if( n % i == 0 )
return 0 ;
return 1 ;
}
如果 n < 2 不是素数 ;
如果 n 是大于 2 的偶数,肯定也不是素数,还多了 2 这个因子 ;
2是素数,不做处理;
从 3 开始枚举,枚举到 sqrt( n ) , 为什么呢? 想一想也可以知道, 假设 n = i * j , 如果 i 和 j 都大于 sqrt( n ) , 那么 i*j 也就大于 n 了,如果只是其中一个大于 sqrt( n ) , 那么相应的另一个就小于 sqrt( n ) 了。为了避免这两个因子的重复判断,只要判断一个更小的就可以了;
这里每次都是 i += 2 , 因为偶数在之前已经淘汰了,现在检验的是奇数,奇数每次 +2 依旧是奇数,这样就减少了一半的判断。
经过计算,10000 以内有 1229 个素数,所以 package 数组大小设为 1230 吧。
如果测试数据比较多,在用 package 数组储存 n 以内的素数也很浪费时间,所以,直接一次性记录所有的素数,再用一个 top 数组记录 10000以内每一个数,小于这个数的最大的素数的位置。以后直接取哪段区间,直接暴力就行了,不用每次都重复储存数组。
#include <stdio.h>
#include <math.h>
#include <string.h>
int n , ans ;
int package[1230] ;
int is[10001] , top[10001] ;
int is_prime( int n ){
if( n < 2 || ( n != 2 && n % 2 == 0 ) )
return 0 ;
int i = 3 ;
for( i = 3 ; i <= sqrt( n ) ; i += 2 )
if( n % i == 0 )
return 0 ;
return 1 ;
}
int main(){
int cnt = 0 ;
for( int i = 2 ; i < 10001 ; ++i ){
if( is_prime( i ) ) // 打表
is[i] = 1 , package[cnt++] = i ;
top[i] = cnt ; // 记录最后一个 < i 的素数的位置
}
while( scanf( "%d" , &n ) && n ){
ans = is[n] ; // ans 初始化为 is[n] , 后面有提前跳出的操作
int i = 2 ;
int count = 0 , j = 0 ;
for( i = 0 ; i < top[n] ; ++i ){
if( package[i] > n/2 ) break ; // 提前跳出
count = 0 ; // count 记录当前枚举加起来的总和
for( j = i ; j < top[n] ; ++j ){
count += package[j] ;
if( count >= n ){ // 如果当前加起来的 >= n
if( count == n )
ans++ ;
break ;
}
}
}
printf( "%d\n" , ans ) ;
}
return 0 ;
}
最近学习了埃氏筛法,判断素数,复杂度O(n)
#include <stdio.h>
#include <math.h>
#include <string.h>
int n , ans ;
int package[1230] , check[10001] ;
int is[10001] , top[10001] ;
void Get_Prime() { // 埃式筛法
int cnt = 0 ;
for( int i = 2 ; i < 10001 ; ++i ) {
if( !check[i] ) // 的确是素数, 加入 package, 标记 is
package[++cnt] = i , is[i] = 1 ;
top[i] = cnt ; // 记录 <= i 的最大素数的位置
for( int j = 1 ; j <= cnt ; ++j ) {
int ans = package[j] ;
if( ans * i > 10000 ) break ;
check[ans * i] = 1 ;
if( i % ans == 0 ) break ; // 已经有最小的因子
}
}
}
int main(){
Get_Prime() ;
while( scanf( "%d" , &n ) && n ){
ans = is[n] ; // ans 初始化为 is[n] , 后面有提前跳出的操作
int i = 2 ;
int count = 0 , j = 0 ;
for( i = 1 ; i <= top[n] ; ++i ){
if( package[i] > n/2 ) break ;
count = 0 ; // count 记录当前枚举加起来的总和
for( j = i ; j < top[n] ; ++j ){
count += package[j] ;
if( count >= n ){ // 如果当前加起来的 >= n
if( count == n )
ans++ ;
break ;
}
}
}
printf( "%d\n" , ans ) ;
}
return 0 ;
}
如有错误,敬请指正,共同学习!