noip模拟赛 洗澡

分析:首先肯定是要用线性筛把素数全部给筛出来的,然后可以维护一个前缀和数组记录1~i个素数的和,对于每一个询问可以从n到1+k枚举它的右端点,然后利用前缀和统计一个长度为K的区间和,看看是不是满足条件.其实这个可以利用二分来加速,然后就做完了.

      二分的时候如果有多个条件需要满足,可以拆分开来讨论l,r怎么移动,最好不要挤在一起写.

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

int T, n, k, prime[1000010], cnt, vis[1000010];
ll sum[1000010];

void init()
{
    for (int i = 2; i <= 1000000; i++)
    {
        if (!vis[i])
            prime[++cnt] = i;
        for (int j = 1; j <= cnt; j++)
        {
            int t = prime[j] * i;
            if (t > 1000000)
                break;
            vis[t] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
    for (int i = 1; i <= cnt; i++)
        sum[i] = sum[i - 1] + prime[i];
}

void solve(int x, int y)
{
    int l = 1, r = cnt, ans = -1;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (mid < k)
            l = mid + 1;
        else
            if (sum[mid] - sum[mid - k] > n)
                r = mid - 1;
            else
                if (mid >= k && sum[mid] - sum[mid - k] <= n)
                {
                    l = mid + 1;
                    ans = mid;
                }
    }
    if (ans == -1)
        printf("-1\n");
    else
    printf("%lld\n", sum[ans] - sum[ans - k]);
}

int main()
{
    init();
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%d", &n, &k);
        solve(n, k);
    }

    return 0;
}

 

posted @ 2017-10-31 23:21  zbtrs  阅读(176)  评论(0编辑  收藏  举报