結果
| 問題 |
No.732 3PrimeCounting
|
| ユーザー |
|
| 提出日時 | 2020-01-15 09:56:25 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
AC
|
| 実行時間 | 1,166 ms / 3,000 ms |
| コード長 | 11,049 bytes |
| コンパイル時間 | 16,179 ms |
| コンパイル使用メモリ | 402,568 KB |
| 実行使用メモリ | 24,176 KB |
| 最終ジャッジ日時 | 2024-12-31 07:57:54 |
| 合計ジャッジ時間 | 31,023 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 89 |
コンパイルメッセージ
warning: unused macro definition: `input`
--> src/main.rs:1:14
|
1 | macro_rules! input {
| ^^^^^
|
= note: `#[warn(unused_macros)]` on by default
warning: unused macro definition: `input_inner`
--> src/main.rs:17:14
|
17 | macro_rules! input_inner {
| ^^^^^^^^^^^
warning: unused macro definition: `read_value`
--> src/main.rs:27:14
|
27 | macro_rules! read_value {
| ^^^^^^^^^^
warning: function `mod_pow` is never used
--> src/main.rs:316:4
|
316 | fn mod_pow(mut a: u64, mut n: u64, m: u64) -> u64 {
| ^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: function `mod_inv` is never used
--> src/main.rs:330:4
|
330 | fn mod_inv(a: u64, m: u64) -> u64 {
| ^^^^^^^
warning: function `garner` is never used
--> src/main.rs:333:4
|
333 | fn garner(mr: &mut Vec<(u64, u64)>, m: u64) -> u64 {
| ^^^^^^
ソースコード
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, ) => {};
// var... 変数の識別子, $t...型を一つよむ
($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::<Vec<_>>()
};
($iter:expr, chars) => {
read_value!($iter, String).chars().collect::<Vec<char>>()
};
($iter:expr, usize1) => {
read_value!($iter, usize) - 1
};
// 配列の最後のNestではここで型が指定されてparseされる
($iter:expr, $t:ty) => {
$iter.next().unwrap().parse::<$t>().expect("Parse error")
};
}
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, ) => {};
// var... 変数の識別子, $t...型を一つよむ
($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::<Vec<_>>()
};
($iter:expr, chars) => {
read_value!($iter, String).chars().collect::<Vec<char>>()
};
($iter:expr, usize1) => {
read_value!($iter, usize) - 1
};
// 配列の最後のNestではここで型が指定されてparseされる
($iter:expr, $t:ty) => {
$iter.next().unwrap().parse::<$t>().expect("Parse error")
};
}
// =========
pub trait ModI:
Sized
+ PartialEq
+ Copy
+ std::ops::Add<Output = Self>
+ std::ops::Sub<Output = Self>
+ std::ops::Mul<Output = Self>
+ std::ops::Div<Output = Self>
+ std::ops::AddAssign
+ std::ops::SubAssign
+ std::ops::MulAssign
+ std::ops::DivAssign
+ std::default::Default
+ std::fmt::Display
+ std::fmt::Debug
{
fn m() -> u64;
fn new(x: u64) -> Self;
fn pow(self, n: u64) -> Self;
fn inv(&self) -> Self;
}
macro_rules! define_modint {
($n:ident,$m:expr) => {
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
struct $n(u64);
#[allow(dead_code)]
impl ModI for $n {
fn m() -> u64 {
$m
}
fn new(x: u64) -> $n {
$n(x % $m)
}
fn pow(self, mut n: u64) -> $n {
let mut ret = $n::new(1);
let mut base = self;
while n > 0 {
if n & 1 == 1 {
ret *= base;
}
base *= base;
n >>= 1;
}
ret
}
fn inv(&self) -> $n {
self.pow($m - 2)
}
}
impl std::default::Default for $n {
fn default() -> $n {
$n::new(0u64)
}
}
impl std::convert::From<u64> for $n {
fn from(x: u64) -> $n {
$n::new(x)
}
}
// Binary operator
impl std::ops::Add for $n {
type Output = $n;
fn add(self, rhs: $n) -> Self::Output {
$n::new(self.0 + rhs.0)
}
}
impl std::ops::Sub for $n {
type Output = $n;
fn sub(self, rhs: $n) -> Self::Output {
if self.0 >= rhs.0 {
$n::new(self.0 - rhs.0)
} else {
$n::new($m - rhs.0 + self.0)
}
}
}
impl std::ops::Mul for $n {
type Output = $n;
fn mul(self, rhs: $n) -> Self::Output {
$n::new(self.0 * rhs.0)
}
}
impl std::ops::Div for $n {
type Output = $n;
fn div(self, rhs: $n) -> Self::Output {
$n::new(self.0 / rhs.0)
}
}
// Assign
impl std::ops::AddAssign for $n {
fn add_assign(&mut self, rhs: $n) {
*self = *self + rhs;
}
}
impl std::ops::SubAssign for $n {
fn sub_assign(&mut self, rhs: $n) {
*self = *self - rhs;
}
}
impl std::ops::MulAssign for $n {
fn mul_assign(&mut self, rhs: $n) {
*self = *self * rhs;
}
}
impl std::ops::DivAssign for $n {
fn div_assign(&mut self, rhs: $n) {
*self = *self / rhs;
}
}
impl std::fmt::Display for $n {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::fmt::Debug for $n {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
};
}
// 10^8 < p < 10^9
// 3 is primitive p-1 root of these
// 167772161 = 5*2^25 + 1, 469762049 = 7*2^26 + 1, 998244353 = 119*2^23 + 1
// 1224736769 = 73 * 2^24 + 1
// define_modint!(ModInt167772161, 167772161);
define_modint!(ModInt998244353, 998244353);
define_modint!(ModInt1224736769, 1224736769);
fn ntt<T: ModI>(a: &mut [T], n: usize, inv: bool) {
// h = log2(n)
let h = {
let mut i = 0;
while 1 << i != n {
i += 1;
}
i
};
let mut j: usize;
for i in 0..n {
j = 0;
for k in 0..h {
// (i >> k & 1)はiのk桁目のbit
// (h - 1 - k)は全体をh-bitとしてk桁目の反対の位置
j |= (i >> k & 1) << (h - 1 - k);
}
// はじめの一回だけひっくりかえす
if i < j {
a.swap(i, j)
};
}
// バタフライ演算
let mut b = 1;
while b < n {
let zeta: T = T::new(3).pow((T::m() - 1) / (2 * b as u64));
for j in 0..b {
// 3 is primitive root of proth prime
// 3 ^ ((m - 1) / (n * j)) is primitive n root's j power
let e: T = if inv {
zeta.pow(j as u64).inv()
} else {
zeta.pow(j as u64)
};
let mut k = 0;
while k < n {
let s: T = a[j + k];
let t: T = a[j + k + b] * e;
a[j + k] = s + t;
a[j + k + b] = s - t;
k += b * 2;
}
}
b *= 2;
}
if inv {
let ni = T::new(n as u64).inv();
for i in 0..n {
a[i] *= ni;
}
}
}
fn mod_conv<T: ModI>(mut a: &mut [T], mut b: &mut [T]) -> Vec<T> {
let n = a.len();
// calc each mod
ntt(&mut a, n, false);
ntt(&mut b, n, false);
let mut c = Vec::with_capacity(n);
for i in 0..n {
c.push(a[i] * b[i]);
}
ntt(&mut c, n, true);
c
}
fn single_convolution<T: ModI>(a: &mut [T], b: &mut [T]) -> Vec<T> {
let d: usize = a.len() + b.len() - 1;
let n = d.checked_next_power_of_two().unwrap();
let mut a = a.to_vec();
a.resize(n, T::new(0));
let mut b = b.to_vec();
b.resize(n, T::new(0));
let mut res = mod_conv(&mut a, &mut b);
res.truncate(d);
res
}
fn mod_pow(mut a: u64, mut n: u64, m: u64) -> u64 {
let mut ret = 1;
while n > 0 {
if n & 1 == 1 {
ret *= a;
ret %= m;
}
a *= a;
a %= m;
n >>= 1;
}
ret
}
// mod mの体におけるaの逆元
fn mod_inv(a: u64, m: u64) -> u64 {
mod_pow(a, m - 2, m)
}
fn garner(mr: &mut Vec<(u64, u64)>, m: u64) -> u64 {
mr.push((m, 0));
// coef... mixed radixの係数, constants... 前まで求めた係数
let mut coef: Vec<u64> = vec![1; mr.len()];
let mut constants: Vec<u64> = vec![0; mr.len()];
for i in 0..mr.len() - 1 {
let v: u64 = (mr[i].1 + mr[i].0 - constants[i]) * mod_inv(coef[i], mr[i].0) % mr[i].0;
for j in i + 1..mr.len() {
constants[j] += coef[j] * v;
constants[j] %= mr[j].0;
coef[j] *= mr[i].0;
coef[j] %= mr[j].0;
}
}
constants[mr.len() - 1]
}
fn primes_under(n: u64) -> Vec<u64> {
let mut primes: Vec<u64> = vec![];
// 素数定理を使え
// x/ln(x)
let mut non_primes = std::collections::HashSet::with_capacity(n as usize / 2);
for i in 2..((n as f64).sqrt() as u64 + 1) {
if non_primes.contains(&i) {
continue;
} else {
primes.push(i);
let mut k = 2;
while i * k <= n {
non_primes.insert(i * k);
k += 1;
}
}
}
for i in ((n as f64).sqrt() as u64 + 1)..n + 1 {
if non_primes.contains(&i) {
continue;
} else {
primes.push(i);
}
}
primes
}
fn main() {
input! {
n:u64,
}
let ps = primes_under(n);
type F0 = ModInt1224736769;
let mut a: Vec<F0> = vec![F0::new(0); ps[ps.len() - 1] as usize + 1];
let mut b: Vec<F0> = vec![F0::new(0); 2 * ps[ps.len() - 1] as usize + 1];
for p in &ps {
a[*p as usize] = F0::new(1);
b[*p as usize * 2] = F0::new(1);
}
let mut res0 = a.clone();
let mut res1 = b.clone();
// all
res0 = single_convolution(
&mut single_convolution(&mut res0, &mut a.clone()),
&mut a.clone(),
);
// two
res1 = single_convolution(&mut res1, &mut a.clone());
let ps3 = primes_under(3 * n);
let mut ans = 0;
for p in &ps3 {
let i = *p as usize;
if i < res1.len() {
ans += (res0[i].0 - 3 * res1[i].0) / 6;
} else if i < res0.len() {
ans += res0[i].0 / 6;
} else {
break;
}
}
println!("{:?}", ans);
}