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\n", count); } return 0; }