struct FenwickTree { val: Vec, } impl FenwickTree { fn new(n: usize) -> Self { FenwickTree { val: vec![0; n + 1], } } fn add(&mut self, mut x: usize, v: usize) { while let Some(p) = self.val.get_mut(x) { *p = p.wrapping_add(v); x += x & (!x + 1); } } fn sum(&mut self, mut x: usize) -> usize { assert!(x < self.val.len()); let mut ans = 0usize; while x > 0 { ans = ans.wrapping_add(self.val[x]); x -= x & (!x + 1); } ans } } // N 以下の素数を列挙 fn sieve(n: usize) -> Vec { let mut is_prime = vec![true; n + 1]; for i in 2.. { if i * i > n { break; } if is_prime[i] { let mut j = i * i; while j <= n { is_prime[j] = false; j += i; } } } let len = is_prime.iter().skip(2).filter(|p| **p).count(); let mut prime = Vec::with_capacity(len); for (i, is_prime) in is_prime.into_iter().enumerate().skip(2) { if is_prime { prime.push(i); } } prime } // N 以下の素数の個数を数える fn prime_count(n: usize) -> usize { if n <= 1 { return 0; } let mut m = 1; while (m + 1) * (m + 1) <= n { m += 1; } let prime = sieve(m); let bound = (n as f64 / (n as f64 + 10.0).log10()).cbrt().powi(2) as usize + 1; let batch = (n as f64).sqrt() as usize + 1; let mut ans = prime.len() - 1; let mut query = vec![vec![]; bound / batch + 1]; let mut stack = vec![(n, prime.len(), 1usize)]; while let Some((n, k, sign)) = stack.pop() { if k == 0 { ans = ans.wrapping_add(sign.wrapping_mul(n)); continue; } let p = prime[k - 1]; if p * p > n { let x = match prime[..k].binary_search_by(|p| p.pow(2).cmp(&n)) { Ok(k) => k + 1, Err(k) => k, }; ans = ans.wrapping_sub(sign.wrapping_mul(k - x)); stack.push((n, x, sign)); } else if n <= bound { query[n / batch].push((n, k, sign)); } else { stack.push((n, k - 1, sign)); stack.push((n / p, k - 1, !sign + 1)); } } let mut sum = vec![0; prime.len()]; for (i, mut query) in query.into_iter().enumerate() { query.sort_by_key(|p| !p.1); let left = i * batch; let right = (i + 1) * batch; let mut is_prime = vec![true; batch]; let mut bit = FenwickTree::new(batch); for i in 1..=batch { bit.add(i, 1); } for (i, &p) in prime.iter().enumerate() { if p >= right { break; } let mut k = (left + p - 1) / p * p; while k < right { let x = k - left; if is_prime[x] { is_prime[x] = false; bit.add(x + 1, !0); } k += p; } while let Some(&(n, k, sign)) = query.last() { if k == i + 1 { let x = n - left; ans = ans.wrapping_add(sign.wrapping_mul(sum[i] + bit.sum(x + 1))); query.pop(); } else { break; } } sum[i] += bit.sum(batch); } } ans } // ---------- begin input macro ---------- // reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 macro_rules! input { (source = $s:expr, $($r:tt)*) => { let mut iter = $s.split_whitespace(); input_inner!{iter, $($r)*} }; ($($r:tt)*) => { let s = { use std::io::Read; let mut s = String::new(); std::io::stdin().read_to_string(&mut s).unwrap(); s }; let mut iter = s.split_whitespace(); input_inner!{iter, $($r)*} }; } macro_rules! input_inner { ($iter:expr) => {}; ($iter:expr, ) => {}; ($iter:expr, $var:ident : $t:tt $($r:tt)*) => { let $var = read_value!($iter, $t); input_inner!{$iter $($r)*} }; } macro_rules! read_value { ($iter:expr, ( $($t:tt),* )) => { ( $(read_value!($iter, $t)),* ) }; ($iter:expr, [ $t:tt ; $len:expr ]) => { (0..$len).map(|_| read_value!($iter, $t)).collect::>() }; ($iter:expr, chars) => { read_value!($iter, String).chars().collect::>() }; ($iter:expr, bytes) => { read_value!($iter, String).bytes().collect::>() }; ($iter:expr, usize1) => { read_value!($iter, usize) - 1 }; ($iter:expr, $t:ty) => { $iter.next().unwrap().parse::<$t>().expect("Parse error") }; } // ---------- end input macro ---------- fn run() { input!(l: usize, r: usize); let mut ans = 0; ans += prime_count(r); ans -= prime_count(l - 1); if r - l >= 1 { ans += prime_count(2 * r - 1); ans -= prime_count(2 * l); } println!("{}", ans); } fn main() { run(); }