Codeforces Round #226 (Div. 2)--C. Bear and Prime Numbers

C. Bear and Prime Numbers
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Recently, the bear started studying data structures and faced the following problem.

You are given a sequence of integers x1, x2, ..., xn of length n and m queries, each of them is characterized by two integers li, ri. Let's introduce f(p) to represent the number of such indexes k, that xk is divisible by p. The answer to the query li, ri is the sum: , where S(li, ri) is a set of prime numbers from segment [li, ri] (both borders are included in the segment).

Help the bear cope with the problem.

Input

The first line contains integer n (1 ≤ n ≤ 106). The second line contains n integers x1, x2, ..., xn (2 ≤ xi ≤ 107). The numbers are not necessarily distinct.

The third line contains integer m (1 ≤ m ≤ 50000). Each of the following m lines contains a pair of space-separated integers, li and ri(2 ≤ li ≤ ri ≤ 2·109) — the numbers that characterize the current query.

Output

Print m integers — the answers to the queries on the order the queries appear in the input.

Sample test(s)
input
6
5 5 7 10 14 15
3
2 11
3 12
4 4
output
9
7
0
input
7
2 3 5 7 11 4 8
2
8 10
2 123
output
0
7
Note

这个题目,也是寒假集训个人赛的一道题目,看到学长们的博客,没想到暴力也能过。
大体题意:
先给你n个数,在给两个整数,l,r作为区间的左右端点,把这区间内的所有素数p找出来,输入f(p)的和,这里f(p)表示素数p能被那n个数整除的个数。
分析:
观察note,发现在 5 5 7 10 14 15 中 f(2) = 2,很显然是10 和 14,说明是xi除以p,而 2 ≤  x i  ≤ 10 7
,虽然右端点最大值是2*10^9,显然当xi取10^7时,大于10^7是肯定不能被整除的,所以这里暗示了,素数数组最大取到10^7。所以数组开到10^7就行,暴力可解!

大体思路:

1.先输入那n个数,a[n]++,a数组的下标就是那n个数,方便后面处理。
2.素数打表,打表的同时,让外层的素数,v[i] += a[j],表明素数能整除的数,这和第一步就联系起来了,如果整除,那就是非0,如果不整除,那就是0,就不加。这里比较巧妙。
3.这里处理输出时,是用到了v数组,v[i]表示前i个数组的f()和,所以输出时,用左右端点做差即可:比如说区间是[l,r],那么输出结果就是v[r] - v[l-1];
4.所以v数组的输入用到了容斥定理。v[i] += v[i-1];
5.最后,输入的左右端点,l,r可能会大于1e+7,大于结果就是0啊,但v数组表示是前i项的f()和,所以此时f(l),f( r)都是0,但v[l],v[r]却不是0,所以把直接让他们等于maxn -1即可,maxn-1是v数组最后一个有意义的数。


代码如下:

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<string>
#include<cstring>
#define mem(x) memset(x,0,sizeof(x));
#define mem1(x) memset(x,-1,sizeof(x));
using namespace std;
const int maxn = 1e7+7;
const int maxt = 1e6+5;
const double eps = 1e-8;
const double pi = acos(-1.0);
typedef long long ll;
typedef unsigned long long llu;
int flag[maxn],v[maxn],a[maxn];
int main()
{
    int n;
    while(~scanf("%d",&n)){
        mem(v);
        mem(a);
        for (int i = 0; i < n; ++i){
            int k;
            scanf("%d",&k);
            a[k]++;
        }
        mem1(flag);
        for (int i = 2; i < maxn; ++i){
            if (flag[i]){
                for (int j = i; j < maxn; j+= i){
                    flag[j] = 0;
                    v[i]+=a[j];
                }
            }
        }
        for (int i =2 ; i < maxn; ++i)
            v[i]+=v[i-1];
        int lef;
        scanf("%d",&lef);
        while(lef--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if (l >= maxn)l=maxn-1;
            if (r >= maxn)r=maxn-1;
            printf("%d\n",v[r]-v[l-1]);
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值