結果
| 問題 |
No.1781 LCM
|
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2021-12-10 14:21:23 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
WA
(最新)
AC
(最初)
|
| 実行時間 | - |
| コード長 | 11,346 bytes |
| コンパイル時間 | 15,876 ms |
| コンパイル使用メモリ | 379,172 KB |
| 実行使用メモリ | 14,536 KB |
| 最終ジャッジ日時 | 2024-11-15 22:22:49 |
| 合計ジャッジ時間 | 45,147 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 30 WA * 1 |
コンパイルメッセージ
warning: unused import: `std::ops::*`
--> src/main.rs:182:5
|
182 | use std::ops::*;
| ^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
ソースコード
// reference: https://twitter.com/shino_skycrew/status/1322841105130422273
use std::ops::*;
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct UVec<T>(pub Vec<T>);
impl<T: Clone> UVec<T> {
pub fn new(ini: T, size: usize) -> Self {
UVec(vec![ini; size])
}
}
impl<T> Deref for UVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for UVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
macro_rules! impl_index {
($x: ty) => {
impl<T> Index<$x> for UVec<T> {
type Output = T;
fn index(&self, index: $x) -> &Self::Output {
unsafe {self.0.get_unchecked(index as usize)}
}
}
impl<T> IndexMut<$x> for UVec<T> {
fn index_mut(&mut self, index: $x) -> &mut Self::Output {
unsafe {self.0.get_unchecked_mut(index as usize)}
}
}
}
}
impl_index!(usize);
impl_index!(u64);
impl_index!(u32);
impl_index!(u16);
impl_index!(i32);
// 初期化配列
// 初期値とサイズを与えて適当にやる系
// 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>,
list: Vec<u32>,
zero: T,
}
impl<T: Copy> InitArray<T> {
pub fn new(zero: T, size: usize) -> Self {
InitArray {
data: vec![zero; size],
list: vec![],
zero: zero,
}
}
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;
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: PartialEq> std::ops::IndexMut<usize> for InitArray<T> {
fn index_mut(&mut self, pos: usize) -> &mut Self::Output {
if self.data[pos] == self.zero {
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 ----------
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> PartialEq for ModInt<T> {
fn eq(&self, rhs: &Self) -> bool {
self.0 == rhs.0
}
}
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
}
}
const MOD: u32 = 998_244_353;
type M = ModInt<ConstantModulo<MOD>>;
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 pow = pow.windows(2).map(|p| p[1] - p[0]).collect::<Vec<_>>();
let pow = UVec(pow);
let sqrt = (2..).find(|p| p * p > m).unwrap() - 1;
let pi = prime_count(m);
let pi = (UVec(pi.0), UVec(pi.1));
let pi = |x: usize| -> usize {
if x <= sqrt {
pi.0[x]
} else {
pi.1[m / x]
}
};
let mut prime = vec![];
enumerate_prime(sqrt + 1000, |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();
let mut last = M::zero();
for p in prime {
let mut calc = |m: usize, v: M| {
ans += M::from(m) * v;
if p <= m {
let mut q = m / p;
let mut add = pi(m) - pi(p - 1) * q;
while q > 1 {
let r = m / q;
let pr = pi(r);
add += pr;
q -= 1;
}
last += M::from(add) * v;
}
};
large.init_with(|d, v| {
let m = m / d;
if p * p > m {
calc(m, v);
} else {
let mut pp = 1;
let mut k = 0;
while d * pp <= sqrt {
let v = v * pow[k];
let d = d * pp;
next_large[d] += v;
k += 1;
pp *= p;
}
let mut m = m / pp;
while m > 0 {
let v = v * pow[k];
next_small[m] += v;
m /= p;
k += 1;
}
}
});
small.init_with(|m, v| {
if p * p > m {
calc(m, v);
} else {
let mut m = m;
let mut k = 0;
while m > 0 {
let v = v * pow[k];
next_small[m] += v;
m /= p;
k += 1;
}
}
});
std::mem::swap(&mut small, &mut next_small);
std::mem::swap(&mut large, &mut next_large);
}
ans += pow[1] * last;
println!("{}", ans);
}
fn main() {
let (n, m) = read();
solve(n, m);
}
akakimidori