From f292aaf64b5f42cb971c40eabf372e9e7f1a3ec9 Mon Sep 17 00:00:00 2001 From: bouzuya Date: Thu, 31 Aug 2023 21:15:07 +0900 Subject: [PATCH] pastbook2 abc190_f --- cargo-compete/pastbook2/Cargo.toml | 1 + cargo-compete/pastbook2/README.md | 1 + cargo-compete/pastbook2/src/bin/302.rs | 600 +++++++++++++++++++++++++ 3 files changed, 602 insertions(+) create mode 100644 cargo-compete/pastbook2/src/bin/302.rs diff --git a/cargo-compete/pastbook2/Cargo.toml b/cargo-compete/pastbook2/Cargo.toml index bd582197..400c9b66 100644 --- a/cargo-compete/pastbook2/Cargo.toml +++ b/cargo-compete/pastbook2/Cargo.toml @@ -56,6 +56,7 @@ edition = "2018" 283 = { alias = "past202107_m", problem = "https://atcoder.jp/contests/past202107-open/tasks/past202107_m" } 290 = { alias = "pastbook2022_g", problem = "https://atcoder.jp/contests/pastbook2022/tasks/pastbook2022_g" } 300 = { alias = "abc185_f", problem = "https://atcoder.jp/contests/abc185/tasks/abc185_f" } +302 = { alias = "abc190_f", problem = "https://atcoder.jp/contests/abc190/tasks/abc190_f" } [dependencies] num = "=0.2.1" diff --git a/cargo-compete/pastbook2/README.md b/cargo-compete/pastbook2/README.md index 6b363e55..4c2fd8ae 100644 --- a/cargo-compete/pastbook2/README.md +++ b/cargo-compete/pastbook2/README.md @@ -52,3 +52,4 @@ - P.283 分割 (第七回 アルゴリズム実技検定:M問題) - P.290 一点更新・区間最小値 (オリジナル問題) - P.300 Range Xor Query (AtCoder Beginner Contest 185:F問題) +- P.302 Shift and Inversions (AtCoder Beginner Contest 190:F問題) diff --git a/cargo-compete/pastbook2/src/bin/302.rs b/cargo-compete/pastbook2/src/bin/302.rs new file mode 100644 index 00000000..42cf40cd --- /dev/null +++ b/cargo-compete/pastbook2/src/bin/302.rs @@ -0,0 +1,600 @@ +use proconio::input; +use segtree::*; + +fn main() { + input! { + n: usize, + a: [usize; n], + } + let mut count = 0_usize; + let mut segtree = Segtree::>::new(n); + for (i, a_i) in a.iter().copied().enumerate() { + segtree.set(a_i, 1); + count += i - segtree.prod(0..a_i); + } + println!("{}", count); + for i in 0..n - 1 { + count += n - 1 - a[i]; + count -= a[i]; + println!("{}", count); + } +} + +//https://github.com/rust-lang-ja/ac-library-rs + +pub mod internal_bit { + // Skipped: + // + // - `bsf` = `__builtin_ctz`: is equivalent to `{integer}::trailing_zeros` + + #[allow(dead_code)] + pub(crate) fn ceil_pow2(n: u32) -> u32 { + 32 - n.saturating_sub(1).leading_zeros() + } + + #[cfg(test)] + mod tests { + #[test] + fn ceil_pow2() { + // https://github.com/atcoder/ac-library/blob/2088c8e2431c3f4d29a2cfabc6529fe0a0586c48/test/unittest/bit_test.cpp + assert_eq!(0, super::ceil_pow2(0)); + assert_eq!(0, super::ceil_pow2(1)); + assert_eq!(1, super::ceil_pow2(2)); + assert_eq!(2, super::ceil_pow2(3)); + assert_eq!(2, super::ceil_pow2(4)); + assert_eq!(3, super::ceil_pow2(5)); + assert_eq!(3, super::ceil_pow2(6)); + assert_eq!(3, super::ceil_pow2(7)); + assert_eq!(3, super::ceil_pow2(8)); + assert_eq!(4, super::ceil_pow2(9)); + assert_eq!(30, super::ceil_pow2(1 << 30)); + assert_eq!(31, super::ceil_pow2((1 << 30) + 1)); + + assert_eq!(32, super::ceil_pow2(u32::max_value())); + } + } +} +pub mod internal_type_traits { + use std::{ + fmt, + iter::{Product, Sum}, + ops::{ + Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, + DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, + SubAssign, + }, + }; + + // Skipped: + // + // - `is_signed_int_t` (probably won't be used directly in `modint.rs`) + // - `is_unsigned_int_t` (probably won't be used directly in `modint.rs`) + // - `to_unsigned_t` (not used in `fenwicktree.rs`) + + /// Corresponds to `std::is_integral` in C++. + // We will remove unnecessary bounds later. + // + // Maybe we should rename this to `PrimitiveInteger` or something, as it probably won't be used in the + // same way as the original ACL. + pub trait Integral: + 'static + + Send + + Sync + + Copy + + Ord + + Not + + Add + + Sub + + Mul + + Div + + Rem + + AddAssign + + SubAssign + + MulAssign + + DivAssign + + RemAssign + + Sum + + Product + + BitOr + + BitAnd + + BitXor + + BitOrAssign + + BitAndAssign + + BitXorAssign + + Shl + + Shr + + ShlAssign + + ShrAssign + + fmt::Display + + fmt::Debug + + fmt::Binary + + fmt::Octal + + Zero + + One + + BoundedBelow + + BoundedAbove + { + } + + /// Class that has additive identity element + pub trait Zero { + /// The additive identity element + fn zero() -> Self; + } + + /// Class that has multiplicative identity element + pub trait One { + /// The multiplicative identity element + fn one() -> Self; + } + + pub trait BoundedBelow { + fn min_value() -> Self; + } + + pub trait BoundedAbove { + fn max_value() -> Self; + } + + macro_rules! impl_integral { + ($($ty:ty),*) => { + $( + impl Zero for $ty { + #[inline] + fn zero() -> Self { + 0 + } + } + + impl One for $ty { + #[inline] + fn one() -> Self { + 1 + } + } + + impl BoundedBelow for $ty { + #[inline] + fn min_value() -> Self { + Self::min_value() + } + } + + impl BoundedAbove for $ty { + #[inline] + fn max_value() -> Self { + Self::max_value() + } + } + + impl Integral for $ty {} + )* + }; +} + + impl_integral!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize); +} +pub mod segtree { + use crate::internal_bit::ceil_pow2; + use crate::internal_type_traits::{BoundedAbove, BoundedBelow, One, Zero}; + use std::cmp::{max, min}; + use std::convert::Infallible; + use std::iter::FromIterator; + use std::marker::PhantomData; + use std::ops::{Add, BitAnd, BitOr, BitXor, Bound, Mul, Not, RangeBounds}; + + // TODO Should I split monoid-related traits to another module? + pub trait Monoid { + type S: Clone; + fn identity() -> Self::S; + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S; + } + + pub struct Max(Infallible, PhantomData S>); + impl Monoid for Max + where + S: Copy + Ord + BoundedBelow, + { + type S = S; + fn identity() -> Self::S { + S::min_value() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + max(*a, *b) + } + } + + pub struct Min(Infallible, PhantomData S>); + impl Monoid for Min + where + S: Copy + Ord + BoundedAbove, + { + type S = S; + fn identity() -> Self::S { + S::max_value() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + min(*a, *b) + } + } + + pub struct Additive(Infallible, PhantomData S>); + impl Monoid for Additive + where + S: Copy + Add + Zero, + { + type S = S; + fn identity() -> Self::S { + S::zero() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + *a + *b + } + } + + pub struct Multiplicative(Infallible, PhantomData S>); + impl Monoid for Multiplicative + where + S: Copy + Mul + One, + { + type S = S; + fn identity() -> Self::S { + S::one() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + *a * *b + } + } + + pub struct BitwiseOr(Infallible, PhantomData S>); + impl Monoid for BitwiseOr + where + S: Copy + BitOr + Zero, + { + type S = S; + fn identity() -> Self::S { + S::zero() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + *a | *b + } + } + + pub struct BitwiseAnd(Infallible, PhantomData S>); + impl Monoid for BitwiseAnd + where + S: Copy + BitAnd + Not + Zero, + { + type S = S; + fn identity() -> Self::S { + !S::zero() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + *a & *b + } + } + + pub struct BitwiseXor(Infallible, PhantomData S>); + impl Monoid for BitwiseXor + where + S: Copy + BitXor + Zero, + { + type S = S; + fn identity() -> Self::S { + S::zero() + } + fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S { + *a ^ *b + } + } + + impl Default for Segtree { + fn default() -> Self { + Segtree::new(0) + } + } + impl Segtree { + pub fn new(n: usize) -> Segtree { + vec![M::identity(); n].into() + } + } + impl From> for Segtree { + fn from(v: Vec) -> Self { + let n = v.len(); + let log = ceil_pow2(n as u32) as usize; + let size = 1 << log; + let mut d = vec![M::identity(); 2 * size]; + d[size..][..n].clone_from_slice(&v); + let mut ret = Segtree { n, size, log, d }; + for i in (1..size).rev() { + ret.update(i); + } + ret + } + } + impl FromIterator for Segtree { + fn from_iter>(iter: T) -> Self { + let iter = iter.into_iter(); + let n = iter.size_hint().0; + let log = ceil_pow2(n as u32) as usize; + let size = 1 << log; + let mut d = Vec::with_capacity(size * 2); + d.extend( + std::iter::repeat_with(M::identity) + .take(size) + .chain(iter) + .chain(std::iter::repeat_with(M::identity).take(size - n)), + ); + let mut ret = Segtree { n, size, log, d }; + for i in (1..size).rev() { + ret.update(i); + } + ret + } + } + impl Segtree { + pub fn set(&mut self, mut p: usize, x: M::S) { + assert!(p < self.n); + p += self.size; + self.d[p] = x; + for i in 1..=self.log { + self.update(p >> i); + } + } + + pub fn get(&self, p: usize) -> M::S { + assert!(p < self.n); + self.d[p + self.size].clone() + } + + pub fn get_slice(&self) -> &[M::S] { + &self.d[self.size..][..self.n] + } + + pub fn prod(&self, range: R) -> M::S + where + R: RangeBounds, + { + // Trivial optimization + if range.start_bound() == Bound::Unbounded && range.end_bound() == Bound::Unbounded { + return self.all_prod(); + } + + let mut r = match range.end_bound() { + Bound::Included(r) => r + 1, + Bound::Excluded(r) => *r, + Bound::Unbounded => self.n, + }; + let mut l = match range.start_bound() { + Bound::Included(l) => *l, + Bound::Excluded(l) => l + 1, + // TODO: There are another way of optimizing [0..r) + Bound::Unbounded => 0, + }; + + assert!(l <= r && r <= self.n); + let mut sml = M::identity(); + let mut smr = M::identity(); + l += self.size; + r += self.size; + + while l < r { + if l & 1 != 0 { + sml = M::binary_operation(&sml, &self.d[l]); + l += 1; + } + if r & 1 != 0 { + r -= 1; + smr = M::binary_operation(&self.d[r], &smr); + } + l >>= 1; + r >>= 1; + } + + M::binary_operation(&sml, &smr) + } + + pub fn all_prod(&self) -> M::S { + self.d[1].clone() + } + + pub fn max_right(&self, mut l: usize, f: F) -> usize + where + F: Fn(&M::S) -> bool, + { + assert!(l <= self.n); + assert!(f(&M::identity())); + if l == self.n { + return self.n; + } + l += self.size; + let mut sm = M::identity(); + while { + // do + while l % 2 == 0 { + l >>= 1; + } + if !f(&M::binary_operation(&sm, &self.d[l])) { + while l < self.size { + l *= 2; + let res = M::binary_operation(&sm, &self.d[l]); + if f(&res) { + sm = res; + l += 1; + } + } + return l - self.size; + } + sm = M::binary_operation(&sm, &self.d[l]); + l += 1; + // while + { + let l = l as isize; + (l & -l) != l + } + } {} + self.n + } + + pub fn min_left(&self, mut r: usize, f: F) -> usize + where + F: Fn(&M::S) -> bool, + { + assert!(r <= self.n); + assert!(f(&M::identity())); + if r == 0 { + return 0; + } + r += self.size; + let mut sm = M::identity(); + while { + // do + r -= 1; + while r > 1 && r % 2 == 1 { + r >>= 1; + } + if !f(&M::binary_operation(&self.d[r], &sm)) { + while r < self.size { + r = 2 * r + 1; + let res = M::binary_operation(&self.d[r], &sm); + if f(&res) { + sm = res; + r -= 1; + } + } + return r + 1 - self.size; + } + sm = M::binary_operation(&self.d[r], &sm); + // while + { + let r = r as isize; + (r & -r) != r + } + } {} + 0 + } + + fn update(&mut self, k: usize) { + self.d[k] = M::binary_operation(&self.d[2 * k], &self.d[2 * k + 1]); + } + } + + // Maybe we can use this someday + // ``` + // for i in 0..=self.log { + // for j in 0..1 << i { + // print!("{}\t", self.d[(1 << i) + j]); + // } + // println!(); + // } + // ``` + + pub struct Segtree + where + M: Monoid, + { + // variable name is _n in original library + n: usize, + size: usize, + log: usize, + d: Vec, + } + + #[cfg(test)] + mod tests { + use crate::segtree::Max; + use crate::Segtree; + use std::ops::{Bound::*, RangeBounds}; + + #[test] + fn test_max_segtree() { + let base = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3]; + let n = base.len(); + let segtree: Segtree> = base.clone().into(); + check_segtree(&base, &segtree); + + let mut segtree = Segtree::>::new(n); + let mut internal = vec![i32::min_value(); n]; + for i in 0..n { + segtree.set(i, base[i]); + internal[i] = base[i]; + check_segtree(&internal, &segtree); + } + + segtree.set(6, 5); + internal[6] = 5; + check_segtree(&internal, &segtree); + + segtree.set(6, 0); + internal[6] = 0; + check_segtree(&internal, &segtree); + } + + //noinspection DuplicatedCode + fn check_segtree(base: &[i32], segtree: &Segtree>) { + let n = base.len(); + #[allow(clippy::needless_range_loop)] + for i in 0..n { + assert_eq!(segtree.get(i), base[i]); + } + + check(base, segtree, ..); + for i in 0..=n { + check(base, segtree, ..i); + check(base, segtree, i..); + if i < n { + check(base, segtree, ..=i); + } + for j in i..=n { + check(base, segtree, i..j); + if j < n { + check(base, segtree, i..=j); + check(base, segtree, (Excluded(i), Included(j))); + } + } + } + assert_eq!( + segtree.all_prod(), + base.iter().max().copied().unwrap_or(i32::min_value()) + ); + for k in 0..=10 { + let f = |&x: &i32| x < k; + for i in 0..=n { + assert_eq!( + Some(segtree.max_right(i, f)), + (i..=n) + .filter(|&j| f(&base[i..j] + .iter() + .max() + .copied() + .unwrap_or(i32::min_value()))) + .max() + ); + } + for j in 0..=n { + assert_eq!( + Some(segtree.min_left(j, f)), + (0..=j) + .filter(|&i| f(&base[i..j] + .iter() + .max() + .copied() + .unwrap_or(i32::min_value()))) + .min() + ); + } + } + } + + fn check(base: &[i32], segtree: &Segtree>, range: impl RangeBounds) { + let expected = base + .iter() + .enumerate() + .filter_map(|(i, a)| Some(a).filter(|_| range.contains(&i))) + .max() + .copied() + .unwrap_or(i32::min_value()); + assert_eq!(segtree.prod(range), expected); + } + } +}