結果
問題 | No.1322 Totient Bound |
ユーザー | akakimidori |
提出日時 | 2021-12-11 01:43:44 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 273 ms / 5,000 ms |
コード長 | 7,219 bytes |
コンパイル時間 | 15,393 ms |
コンパイル使用メモリ | 377,048 KB |
実行使用メモリ | 7,680 KB |
最終ジャッジ日時 | 2024-07-19 00:57:46 |
合計ジャッジ時間 | 21,443 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,376 KB |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 2 ms
5,376 KB |
testcase_04 | AC | 2 ms
5,376 KB |
testcase_05 | AC | 2 ms
5,376 KB |
testcase_06 | AC | 2 ms
5,376 KB |
testcase_07 | AC | 2 ms
5,376 KB |
testcase_08 | AC | 2 ms
5,376 KB |
testcase_09 | AC | 2 ms
5,376 KB |
testcase_10 | AC | 2 ms
5,376 KB |
testcase_11 | AC | 2 ms
5,376 KB |
testcase_12 | AC | 1 ms
5,376 KB |
testcase_13 | AC | 3 ms
5,376 KB |
testcase_14 | AC | 2 ms
5,376 KB |
testcase_15 | AC | 2 ms
5,376 KB |
testcase_16 | AC | 2 ms
5,376 KB |
testcase_17 | AC | 3 ms
5,376 KB |
testcase_18 | AC | 45 ms
5,376 KB |
testcase_19 | AC | 65 ms
5,376 KB |
testcase_20 | AC | 207 ms
6,784 KB |
testcase_21 | AC | 226 ms
6,912 KB |
testcase_22 | AC | 229 ms
6,912 KB |
testcase_23 | AC | 271 ms
7,424 KB |
testcase_24 | AC | 272 ms
7,424 KB |
testcase_25 | AC | 271 ms
7,680 KB |
testcase_26 | AC | 269 ms
7,424 KB |
testcase_27 | AC | 272 ms
7,424 KB |
testcase_28 | AC | 272 ms
7,680 KB |
testcase_29 | AC | 270 ms
7,552 KB |
testcase_30 | AC | 2 ms
5,376 KB |
testcase_31 | AC | 2 ms
5,376 KB |
testcase_32 | AC | 2 ms
5,376 KB |
testcase_33 | AC | 270 ms
7,424 KB |
testcase_34 | AC | 271 ms
7,424 KB |
testcase_35 | AC | 273 ms
7,552 KB |
testcase_36 | AC | 268 ms
7,552 KB |
testcase_37 | AC | 268 ms
7,424 KB |
testcase_38 | AC | 270 ms
7,552 KB |
ソースコード
// ---------- begin miller-rabin ---------- fn is_prime_miller(n: u64) -> bool { if n <= 1 { return false; } else if n <= 3 { return true; } else if n % 2 == 0 { return false; } let pow = |r: u64, mut m: u64| -> u64 { let mut t = 1u128; let mut s = (r % n) as u128; let n = n as u128; while m > 0 { if m & 1 == 1 { t = t * s % n; } s = s * s % n; m >>= 1; } t as u64 }; let mut d = n - 1; let mut s = 0; while d % 2 == 0 { d /= 2; s += 1; } const B: [u64; 7] = [2, 325, 9375, 28178, 450775, 9780504, 1795265022]; for &b in B.iter() { let mut a = pow(b, d); if a <= 1 { continue; } let mut i = 0; while i < s && a != n - 1 { i += 1; a = (a as u128 * a as u128 % n as u128) as u64; } if i >= s { return false; } } true } // ---------- end miller-rabin ---------- // 初期化配列 // 初期値とサイズを与えて適当にやる系 // new(size, zero): zero埋めした長さsizeの配列を返す // init(&mut self): 初期化 // index(mut) でアクセスしたときその履歴を溜め込む // それ以外でアクセスすると死ぬので注意 // // 考えるべきこと // 1. deref で dataへアクセスできるようにしていいか // derefmut はダメ // 2. 今のままだと二次元配列の初期化とかには対応できない // なんか方法を考えたい // ---------- begin init array ---------- #[derive(Clone)] pub struct InitArray<T> { data: Vec<T>, used: Vec<bool>, list: Vec<u32>, zero: T, } impl<T: Copy> InitArray<T> { pub fn new(zero: T, size: usize) -> Self { InitArray { data: vec![zero; size], used: vec![false; size], list: vec![], zero: zero, } } pub fn init(&mut self) { self.init_with(|_, _| ()); } pub fn init_with<F>(&mut self, mut f: F) where F: FnMut(usize, T), { for x in self.list.drain(..) { let x = x as usize; self.used[x] = false; let v = std::mem::replace(&mut self.data[x], self.zero); f(x, v); } } } impl<T> std::ops::Index<usize> for InitArray<T> { type Output = T; fn index(&self, pos: usize) -> &Self::Output { &self.data[pos] } } impl<T> std::ops::IndexMut<usize> for InitArray<T> { fn index_mut(&mut self, pos: usize) -> &mut Self::Output { if !self.used[pos] { self.used[pos] = true; self.list.push(pos as u32); } &mut self.data[pos] } } // ---------- end init array ---------- // ---------- begin prime count ---------- // 処理が終わった時 // large[i]: pi(floor(n / i)) // small[i]: pi(i) // となっている // O(N^(3/4)/log N) pub fn prime_count(n: usize) -> (Vec<usize>, Vec<usize>) { if n <= 1 { return (vec![0, 0], vec![0, 0]); } let sqrt = (1..).find(|p| p * p > n).unwrap() - 1; let mut large = vec![0; sqrt + 1]; let mut small = vec![0; sqrt + 1]; for (i, (large, small)) in large.iter_mut().zip(&mut small).enumerate().skip(1) { *large = n / i - 1; *small = i - 1; } for p in 2..=sqrt { if small[p] == small[p - 1] { continue; } let pi = small[p] - 1; let q = p * p; for i in 1..=sqrt.min(n / q) { large[i] -= *large.get(i * p).unwrap_or_else(|| &small[n / (i * p)]) - pi; } for i in (q..=sqrt).rev() { small[i] -= small[i / p] - pi; } } (small, large) } // ---------- end prime count ---------- // ---------- begin enumerate prime ---------- fn enumerate_prime<F>(n: usize, mut f: F) where F: FnMut(usize), { assert!(1 <= n && n <= 5 * 10usize.pow(8)); let batch = (n as f64).sqrt().ceil() as usize; let mut is_prime = vec![true; batch + 1]; for i in (2..).take_while(|p| p * p <= batch) { if is_prime[i] { let mut j = i * i; while let Some(p) = is_prime.get_mut(j) { *p = false; j += i; } } } let mut prime = vec![]; for (i, p) in is_prime.iter().enumerate().skip(2) { if *p && i <= n { f(i); prime.push(i); } } let mut l = batch + 1; while l <= n { let r = std::cmp::min(l + batch, n + 1); is_prime.clear(); is_prime.resize(r - l, true); for &p in prime.iter() { let mut j = (l + p - 1) / p * p - l; while let Some(is_prime) = is_prime.get_mut(j) { *is_prime = false; j += p; } } for (i, _) in is_prime.iter().enumerate().filter(|p| *p.1) { f(i + l); } l += batch; } } // ---------- end enumerate prime ---------- fn read() -> usize { let mut s = String::new(); std::io::stdin().read_line(&mut s).unwrap(); s.trim().parse().unwrap() } fn solve(n: usize) { let sqrt = (2..).find(|p| p * p > n).unwrap() - 1; let mut pi = prime_count(n); for i in 1..=sqrt { if is_prime_miller(i as u64 + 1) { pi.0[i] += 1; } if is_prime_miller((n / i) as u64 + 1) { pi.1[i] += 1; } } let pi = |x: usize| -> usize { let x = x - 1; if x < pi.0.len() { pi.0[x] } else { pi.1[n / x] } }; let mut prime = vec![]; enumerate_prime(sqrt + 100000, |p| prime.push(p)); let mut large = InitArray::new(0, sqrt + 1); let mut small = InitArray::new(0, sqrt + 1); let mut next_large = InitArray::new(0, sqrt + 1); let mut next_small = InitArray::new(0, sqrt + 1); large[1] = 1usize; let mut ans = 0; for (i, &p) in prime.iter().enumerate() { let mut prun = |m: usize, v: usize| -> bool { (p - 1) * p > m && { ans += v; if p <= m + 1 { ans += v * (pi(m + 1) - i); } true } }; large.init_with(|d, v| { let m = n / d; if prun(m, v) { return; } next_large[d] += v; let mut d = d * (p - 1); while d <= sqrt { next_large[d] += v; d *= p; } let mut m = n / d; while m > 0 { next_small[m] += v; m /= p; } }); small.init_with(|m, v| { if prun(m, v) { return; } next_small[m] += v; let mut m = m / (p - 1); while m > 0 { next_small[m] += v; m /= p; } }); std::mem::swap(&mut small, &mut next_small); std::mem::swap(&mut large, &mut next_large); } println!("{}", ans); } fn main() { solve(read()); }