筛法,区间问题(RGCDQ,HDU 5317)

本文探讨了筛法及线性筛的应用,并通过实例介绍了如何利用这些方法解决区间问题。主要内容包括一维差分算法的使用,以及如何通过前缀和等技巧快速找出区间内符合条件的整数。

从一开始学筛法及其优化的时候就只是一知半解,所以需要用到其变化的时候就开始暴露问题。

顺便学了一下线性筛:

http://blog.youkuaiyun.com/xl2015190026/article/details/72859366


理应想到应用区间问题的解法的,思路都是前缀和。只不过跟数位有关的问题就用数位计数DP求前缀和,最简单的前缀和就是O(n)加起来。

这里的前缀和是指个数的前缀和,也就是所谓的一维差分算法,用于快速找区间内满足条件的数的个数。

区间问题是指多次询问一个区间里面满足特定条件的数的个数。

本题不是区间问题,因为既不是问数的个数,也不是单纯的只考虑每一个数,因此前缀和或是线段树都没有办法很好的解决。

但是由于题目的特殊性,所以可以转化成区间问题再来讨论求解。


代码

#include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1000010;

int F[maxn];
vector<int>vec[10];
int cnt[10];

void init()
{
    for(int i=2;i<maxn;i++) if(!F[i])
        for(int j=i;j<maxn;j+=i) F[j]++;
    for(int i=2;i<maxn;i++) if(F[i]>=3) vec[F[i]].push_back(i);
}

int solve()
{
    int L,R;
    scanf("%d %d",&L,&R);
    int l,r;

    l=lower_bound(vec[7].begin(),vec[7].end(),L)-vec[7].begin();
    r=upper_bound(vec[7].begin(),vec[7].end(),R)-vec[7].begin();
    if(r-l>=2) return 0*puts("7");

    l=lower_bound(vec[6].begin(),vec[6].end(),L)-vec[6].begin();
    r=upper_bound(vec[6].begin(),vec[6].end(),R)-vec[6].begin();
    if(r-l>=2) return 0*puts("6");

    l=lower_bound(vec[5].begin(),vec[5].end(),L)-vec[5].begin();
    r=upper_bound(vec[5].begin(),vec[5].end(),R)-vec[5].begin();
    if(r-l>=2) return 0*puts("5");

    l=lower_bound(vec[4].begin(),vec[4].end(),L)-vec[4].begin();
    r=upper_bound(vec[4].begin(),vec[4].end(),R)-vec[4].begin();
    if(r-l>=2) return 0*puts("4");

    l=lower_bound(vec[3].begin(),vec[3].end(),L)-vec[3].begin();
    r=upper_bound(vec[3].begin(),vec[3].end(),R)-vec[3].begin();
    if(r-l>=2) return 0*puts("3");

    memset(cnt,0,sizeof(cnt));
    for(int i=L;i<=R;i++) cnt[F[i]]++;
    if(cnt[6]&&cnt[3]) return 0*puts("3");
    if(cnt[2]&&cnt[4]) return 0*puts("2");
    if(cnt[2]&&cnt[6]) return 0*puts("2");
    if(cnt[4]&&cnt[6]) return 0*puts("2");
    if(cnt[2]>=2) return 0*puts("2");
    return 0*puts("1");
}

int main()
{
    init();
    //for(int i=0;i<=1000;i++) printf("F(%d):%d\n",i,F[i]);
    int T;
    scanf("%d",&T);
    while(T--) solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值