poj_2739 尺取法

题目大意

    给定一个数字N,N可能由1个或多个连续的素数求和得到,比如41 = 2+3+5+7+11+13, 41 = 11+13+17, 41 = 41。求出对于N,所有可能的组合形式。

题目分析

    先求出所有可能构成加数的素数,使用埃氏筛选法。然后求出所有的可能形式,由于所选择的是一个连续的区间,可以使用一个头指针,一个尾指针,区间选择为头尾指针内部的区域,通过头尾指针的移动来更改区间。即尺取法。 
    尾部保持不动,不断增加头部,并加上头部数据,记录区间内的和,若恰好等于n,则计数加1,若大于等于n,则不断的减去尾部的数据....

实现(c++)

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<cmath>
using namespace std;
bool is_primes[10005];
int primes[10005];
int prime_count;
//埃氏筛法 求质数
void GetPrimes(int n){
	int k = 0;
	memset(is_primes, true, sizeof(is_primes));
	for (int i = 2; i <= n; i++){
		if (!is_primes[i])
			continue;
		primes[k++] = i;
		for (int m = 1; m*i <= n; m++)
			is_primes[m*i] = false;
	}
	prime_count = k;
}
int main(){
	int n;
	GetPrimes(10000);	//获得10000 以内的所有质数

	while (scanf("%d", &n) && n){
		int sum = 0;
		int s = 0, t = 0;
		int count = 0;
		//尺取法
		for (;;){
			while (primes[t] <= n && sum < n){	//若小于n则头部一直增加,直到大于等于n
				sum += primes[t++];
			}
			if (sum == n)	//计数
				count++;
			
			sum -= primes[s++];	//减去头部
			
			if (sum <= 0)	//说明尾部一直没有增加,且头部赶上了尾部,结束
				break;
		}
		printf("%d
", count);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/gtarcoder/p/4908524.html