我这里显示离散化了2-1000的质数,把集合1-index,每个对应质数2,3,5,7,11…
我们可以知道如果查询的是n,又需要质数连续,假设i-j区间和为n,则ans++。这就是最朴素的思路。
我们顺着这个思路假设用最古老的方法,先遍历一遍已经做好的集合,算出sum,这样太慢了。
我们看到这道题用在了,单点更新,求区间前缀和,想到最快的方法,就是树状数组了。
那么就用树状数组来求前缀和就好了。
其中每个区间用尺取法来维护。
14ms就能跑出答案了。
注意尺取法的时候,r和l的取最大时候的取值。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pir;
int n;
bool use[10005];
int temp[10005];
int index = 1;
int mp[10005];
int lowbit(int i)
{
return i & (-i);
}//求下一个i需要加减的值
void add(int i, int k)
{
while (i < index)
{
temp[i] += k;
i += lowbit(i);
}
}//添加
void prime()
{
for (int i = 2; i <= 10000; i++)
{
for (int j = i + i; j <= 10000; j += i)
{
if (use[j])
use[j] = false;
}
}
up(i, 1, 10001)
{
if (use[i])
{
//cout << i << endl;
mp[index] = i;
index++;
}
}
up(i, 1, index)
{
add(i,mp[i]);
}
}//离散化素数
int qsum(int i)
{
int sum = 0;
while (i)
{
sum += temp[i];
i -= lowbit(i);
}
return sum;
}//树状数组求和
int main()
{
fill(use, use+10001, true);
use[0] = use[1] = false;
int lf, rt; int ans;
prime();//初始化
while (scanf("%d", &n) && n)
{
lf = 0;
rt = 1;
ans = 0;
int temp = lower_bound(mp, mp + 10005, n)-mp+1;//查找一下下标为最大下标
while (lf < rt&&rt<=temp)//尺取法
{
if (qsum(rt) - qsum(lf) <n)
rt++;
else if(qsum(rt)-qsum(lf)==n)
{
ans++;
lf++;
}
else lf++;
}
cout << ans << endl;
}
return 0;
}