結果
| 問題 |
No.1781 LCM
|
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2021-12-10 08:47:17 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 11,112 bytes |
| コンパイル時間 | 22,322 ms |
| コンパイル使用メモリ | 378,884 KB |
| 実行使用メモリ | 384,260 KB |
| 最終ジャッジ日時 | 2024-07-18 02:28:01 |
| 合計ジャッジ時間 | 29,179 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | -- * 2 |
| other | AC * 21 TLE * 1 -- * 9 |
コンパイルメッセージ
warning: type alias `Map` is never used
--> src/main.rs:305:6
|
305 | type Map<K, V> = HashMap<K, V>;
| ^^^
|
= note: `#[warn(dead_code)]` on by default
warning: function `naive` is never used
--> src/main.rs:395:4
|
395 | fn naive(n: usize, m: usize) {
| ^^^^^
ソースコード
// 初期化配列
// 初期値とサイズを与えて適当にやる系
// 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<usize>,
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) {
for x in self.list.drain(..) {
self.used[x] = false;
self.data[x] = self.zero;
}
}
pub fn init_with<F>(&mut self, mut f: F)
where
F: FnMut(usize, T),
{
for x in self.list.drain(..) {
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);
}
&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 ----------
use std::marker::*;
use std::ops::*;
pub trait Modulo {
fn modulo() -> u32;
}
pub struct ConstantModulo<const M: u32>;
impl<const M: u32> Modulo for ConstantModulo<{ M }> {
fn modulo() -> u32 {
M
}
}
pub struct ModInt<T>(u32, PhantomData<T>);
impl<T> Clone for ModInt<T> {
fn clone(&self) -> Self {
Self::new_unchecked(self.0)
}
}
impl<T> Copy for ModInt<T> {}
impl<T: Modulo> Add for ModInt<T> {
type Output = ModInt<T>;
fn add(self, rhs: Self) -> Self::Output {
let mut v = self.0 + rhs.0;
if v >= T::modulo() {
v -= T::modulo();
}
Self::new_unchecked(v)
}
}
impl<T: Modulo> AddAssign for ModInt<T> {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl<T: Modulo> Sub for ModInt<T> {
type Output = ModInt<T>;
fn sub(self, rhs: Self) -> Self::Output {
let mut v = self.0 - rhs.0;
if self.0 < rhs.0 {
v += T::modulo();
}
Self::new_unchecked(v)
}
}
impl<T: Modulo> SubAssign for ModInt<T> {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl<T: Modulo> Mul for ModInt<T> {
type Output = ModInt<T>;
fn mul(self, rhs: Self) -> Self::Output {
let v = self.0 as u64 * rhs.0 as u64 % T::modulo() as u64;
Self::new_unchecked(v as u32)
}
}
impl<T: Modulo> MulAssign for ModInt<T> {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<T: Modulo> Neg for ModInt<T> {
type Output = ModInt<T>;
fn neg(self) -> Self::Output {
if self.is_zero() {
Self::zero()
} else {
Self::new_unchecked(T::modulo() - self.0)
}
}
}
impl<T> std::fmt::Display for ModInt<T> {
fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> std::fmt::Debug for ModInt<T> {
fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> Default for ModInt<T> {
fn default() -> Self {
Self::zero()
}
}
impl<T: Modulo> std::str::FromStr for ModInt<T> {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let val = s.parse::<u32>()?;
Ok(ModInt::new(val))
}
}
impl<T: Modulo> From<usize> for ModInt<T> {
fn from(val: usize) -> ModInt<T> {
ModInt::new_unchecked((val % T::modulo() as usize) as u32)
}
}
impl<T: Modulo> From<u64> for ModInt<T> {
fn from(val: u64) -> ModInt<T> {
ModInt::new_unchecked((val % T::modulo() as u64) as u32)
}
}
impl<T> ModInt<T> {
pub fn new_unchecked(n: u32) -> Self {
ModInt(n, PhantomData)
}
pub fn zero() -> Self {
ModInt::new_unchecked(0)
}
pub fn one() -> Self {
ModInt::new_unchecked(1)
}
pub fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl<T: Modulo> ModInt<T> {
pub fn new(d: u32) -> Self {
ModInt::new_unchecked(d % T::modulo())
}
pub fn pow(&self, mut n: u64) -> Self {
let mut t = Self::one();
let mut s = *self;
while n > 0 {
if n & 1 == 1 {
t *= s;
}
s *= s;
n >>= 1;
}
t
}
pub fn inv(&self) -> Self {
assert!(!self.is_zero());
self.pow(T::modulo() as u64 - 2)
}
}
type M = ModInt<ConstantModulo<998_244_353>>;
use std::collections::*;
type Map<K, V> = HashMap<K, V>;
fn read() -> (usize, usize) {
let mut s = String::new();
std::io::stdin().read_line(&mut s).unwrap();
let a = s
.trim()
.split_whitespace()
.flat_map(|s| s.parse())
.collect::<Vec<_>>();
(a[0], a[1])
}
fn solve(n: usize, m: usize) {
let mut pow = vec![M::zero(); 40 + 1];
for i in 1..=40 {
pow[i] = M::from(i).pow(n as u64);
}
let sqrt = (2..).find(|p| p * p > m).unwrap() - 1;
let pi = prime_count(m);
let pi = |x: usize| -> usize {
assert!(x <= m);
if x <= sqrt {
return pi.0[x];
}
let q = m / x;
let r = m / q;
assert_eq!(x, r);
pi.1[q]
};
let mut prime = vec![];
enumerate_prime(sqrt + 200, |p| prime.push(p));
let mut large = InitArray::new(M::zero(), sqrt + 1);
let mut small = InitArray::new(M::zero(), sqrt + 1);
let mut next_large = InitArray::new(M::zero(), sqrt + 1);
let mut next_small = InitArray::new(M::zero(), sqrt + 1);
large[1] = M::one();
let mut ans = M::zero();
for (i, &p) in prime.iter().enumerate() {
large.init_with(|d, v| {
let m = m / d;
if p.pow(2) > m {
ans += v * M::from(m);
let mut l = p;
let mut q = m / l;
while q > 0 {
let r = m / q;
let cnt = pi(r) - if l == p { i } else { pi(l - 1) };
ans += v * M::from(q * cnt) * (pow[2] - M::one());
l = r + 1;
q -= 1;
}
} else {
for k in (0usize..).take_while(|k| p.pow(*k as u32) <= m) {
let v = v * (pow[k + 1] - pow[k]);
let pp = p.pow(k as u32);
if pp * d <= sqrt {
next_large[d * pp] += v;
} else {
next_small[m / pp] += v;
}
}
}
});
small.init_with(|m, v| {
if p.pow(2) > m {
ans += v * M::from(m);
let mut l = p;
let mut q = m / l;
while q > 0 {
let r = m / q;
let cnt = pi(r) - if l == p { i } else { pi(l - 1) };
ans += v * M::from(q * cnt) * (pow[2] - M::one());
l = r + 1;
q -= 1;
}
} else {
for k in (0usize..).take_while(|k| p.pow(*k as u32) <= m) {
let v = v * (pow[k + 1] - pow[k]);
let pp = p.pow(k as u32);
next_small[m / pp] += v;
}
}
});
std::mem::swap(&mut small, &mut next_small);
std::mem::swap(&mut large, &mut next_large);
}
println!("{}", ans);
}
fn naive(n: usize, m: usize) {
let mut dp = vec![M::one(); m + 1];
enumerate_prime(m, |p| {
for i in 1..=(m / p) {
dp[p * i] = dp[p * i] + dp[i];
}
});
for dp in dp.iter_mut() {
*dp = dp.pow(n as u64);
}
enumerate_prime(m, |p| {
for i in (1..=(m / p)).rev() {
dp[p * i] = dp[p * i] - dp[i];
}
});
let mut ans = M::zero();
for i in 1..=m {
ans += M::from(m / i) * dp[i];
}
println!("{}", ans);
}
fn main() {
let (n, m) = read();
solve(n, m);
}
akakimidori