ACM训练二E题

题意:给你一个闭区间[a,b],求一个最小的L,使得在区间[a,b-L+1]内任取一个数x,可以满足在x,x+1,x+2,……,x+L-2,x+L-1内至少包含k个素数。(1<=a,b,k<=10^6)
•考察内容:筛素数、二分
•一边筛素数,一边处理出一个前缀和sum
•sum(i)表示[1,i]中有多少素数
•那么我们每次查询区间[l,r]中有多少素数,直接查sum[r]-sum[l-1]就可以了
•接下去我们按照题意,对答案L进行二分就可以了
这是陶叔的解释
我的解释全在注释里头了
#include<iostream>
using namespace std;
int a,b,k;
int sum[1000010];//默认的值为0
int pri[1000010];//筛选后的素数保存在此数组中

//筛选1-b的素数
void init()
{
    for(int i = 2;i < 1000010;i++)
    {
        sum[i] = sum[i-1];
        if(pri[i])//如果不是素数就跳过
        {

            continue;
        }
        sum[i]++;//否则就在前一个的基础上++
        for(int j =i + i;j < 1000010;j+= i)//把所有为i倍数的标记为1,代表非素数
        {

            pri[j] = 1;
        }
    }
}

//检测这个mid值是否满足条件
bool check(int mid)
{

    for(int i = a;i <= b - mid +1;i++)
    {

        if(sum[i+mid - 1] - sum[i -1] < k)//判断i到i+mid中是否素数至少为k个
        {

            return 0;
        }
    }
    return 1;
}

int main()
{

    init();
    cin >> a >> b >> k;

    //若整个区间的素数少于k个,直接输出-1结束
    if(sum[b] - sum[a -1] < k)
    {

        cout << "-1" << endl;
        return 0;
    }

    //采用二分法找L
    int l = 1,r = b - a +1,ans;
    while(l <= r)
    {

        int mid = (l + r) >> 1;
        if(check(mid))
        {

            ans = mid; r = mid-1;
        }
        else
        {

            l = mid + 1;
        }
    }
    cout << ans << endl;
    return 0;
}

重点还是要培养二分的意识

 
posted @ 2014-07-29 15:50  木马惜君  阅读(111)  评论(0编辑  收藏  举报