Problem:
Score : 400 points

Problem Statement

We say that a odd number N is similar to 2017 when both N and (N+1)/2 are prime.

You are given Q queries.

In the i-th query, given two odd numbers l_i and r_i, find the number of odd numbers x similar to 2017 such that l_i ≤ x ≤ r_i.

Constraints

1≤Q≤10^5

1≤l_i≤r_i≤10^5

l_i and r_i are odd.

All input values are integers.

Input

Input is given from Standard Input in the following format:

Q
l_1 r_1
:
l_Q r_Q

Output

Print Q lines. The i-th line (1≤i≤Q) should contain the response to the i-th query.

Sample Input 1

1
3 7

Sample Output 1

2

3 is similar to 2017, since both 3 and (3+1)/2=2 are prime.

5 is similar to 2017, since both 5 and (5+1)/2=3 are prime.

7 is not similar to 2017, since (7+1)/2=4 is not prime, although 7 is prime.

Thus, the response to the first query should be 2.

Sample Input 2

4
13 13
7 11
7 11
2017 2017

Sample Output 2

1
0
0
1

Note that 2017 is also similar to 2017.

Sample Input 3

6
1 53
13 91
37 55
19 51
73 91
13 49

Sample Output 3

4
4
1
1
1
2

Solution in Rust (1.42.0) (judge verdict: Accepted)

fn primes(n: usize) -> Vec<usize> {
    let mut table = (2..=n).collect::<Vec<_>>();
    let mut primes = vec![];
    for i in 0..table.len() {
        let prime_candidate = table[i];
        if prime_candidate != 0 {
            primes.push(prime_candidate);
            for j in (i + prime_candidate..table.len()).step_by(prime_candidate) {
                table[j] = 0;
            }
        }
    }
    primes
}

pub trait BinarySearch<T> {
    fn lower_bound(&self, x: &T) -> usize;
    fn upper_bound(&self, x: &T) -> usize;
}

impl<T: Ord> BinarySearch<T> for [T] {
    fn lower_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                std::cmp::Ordering::Less => {
                    low = mid + 1;
                }
                std::cmp::Ordering::Equal | std::cmp::Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }

    fn upper_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                std::cmp::Ordering::Less | std::cmp::Ordering::Equal => {
                    low = mid + 1;
                }
                std::cmp::Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }
}

#[test]
fn test_binary_search() {
    let v = vec![1, 3, 4, 4, 4, 6, 7, 12, 54, 60];

    assert_eq!(v.lower_bound(&4), 2);
    assert_eq!(v.upper_bound(&4), 5);
    assert_eq!(v.lower_bound(&2), 1);
    assert_eq!(v.upper_bound(&2), 1);
}

fn main() {
    proconio::input! {
        q: usize,
        lrs: [(usize, usize); q],
    }
    let primes = primes(100000);
    let like2017s = primes
        .iter()
        .filter(|&&prime| {
            let another_prime_candidate = (prime + 1) / 2;
            let i = primes.lower_bound(&another_prime_candidate);
            i < primes.len() && primes[i] == another_prime_candidate
        })
        .collect::<Vec<_>>();
    for (l, r) in lrs {
        let ans = like2017s.upper_bound(&&r) - like2017s.lower_bound(&&l);
        println!("{}", ans);
    }
}