POJ 2739 Sum of Consecutive Prime Numbers 暴力枚举+素数判断

 Sum of Consecutive Prime Numbers

 


题目描述

Some positive integers can be represented by a sum of one or more consecutive prime numbers. How many such representations does a given positive integer have? For example, the integer 53 has two representations 5 + 7 + 11 + 13 + 17 and 53. The integer 41 has three representations 2+3+5+7+11+13, 11+13+17, and 41. The integer 3 has only one representation, which is 3. The integer 20 has no such representations. Note that summands must be consecutive prime 
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.
Input
The input is a sequence of positive integers each in a separate line. The integers are between 2 and 10 000, inclusive. The end of the input is indicated by a zero.
Output
The output should be composed of lines each corresponding to an input line except the last zero. An output line includes the number of representations for the input integer as the sum of one or more consecutive prime numbers. No other characters should be inserted in the output.
Sample Input
2
3
17
41
20
666
12
53
0
Sample 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 ;  
}  


如有错误,敬请指正,共同学习!


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值