Skip to content

Commit

Permalink
convert some old problems to new i/o approach
Browse files Browse the repository at this point in the history
Signed-off-by: Lance-Drane <ldraneutk@gmail.com>
  • Loading branch information
Lance-Drane committed Jul 14, 2024
1 parent e3c7a82 commit beebe96
Show file tree
Hide file tree
Showing 16 changed files with 2,316 additions and 676 deletions.
66 changes: 25 additions & 41 deletions src/bin/additional_multiplication_table.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
// I/O boilerplate //

pub struct UnsafeScanner<'a> {
// not actually dead code, needed for buf_iter to work
#[allow(dead_code)]
buf_str: Vec<u8>,
buf_iter: std::str::SplitAsciiWhitespace<'a>,
}
use std::io::Read;

impl UnsafeScanner<'_> {
pub fn new<R: std::io::Read>(mut reader: R) -> Self {
let mut buf_str = vec![];
unsafe {
reader.read_to_end(&mut buf_str).unwrap_unchecked();
}
let buf_iter = unsafe {
let slice = std::str::from_utf8_unchecked(&buf_str);
std::mem::transmute::<
std::str::SplitAsciiWhitespace<'_>,
std::str::SplitAsciiWhitespace<'_>,
>(slice.split_ascii_whitespace())
};

Self { buf_str, buf_iter }
}
pub trait PosInt {
fn to_posint(buf: &[u8]) -> Self;
}

/// Use "turbofish" syntax `token::<T>()` to select data type of next token.
///
/// # Panics
/// Panics if there's no more tokens or if the token cannot be parsed as T.
pub fn token<T: std::str::FromStr>(&mut self) -> T {
unsafe {
self.buf_iter
.next()
.unwrap_unchecked()
.parse()
.unwrap_unchecked()
}
macro_rules! impl_int {
(for $($t:ty),+) => {
$(impl PosInt for $t {
#[allow(clippy::cast_lossless, clippy::cast_possible_wrap)]
fn to_posint(buf: &[u8]) -> Self {
unsafe {
buf.iter()
.map(|byte| (byte & 15) as $t)
.reduce(|acc, digit| acc * 10 + digit)
.unwrap_unchecked()
}
}
})*
}
}
impl_int!(for u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

// problem //

Expand Down Expand Up @@ -66,8 +50,8 @@ impl UnsafeScanner<'_> {
/// <ul>
/// <li>1 ≤ n < 10<sup>6</sup></li>
/// </ul>
fn solve<W: std::io::Write>(mut scan: UnsafeScanner, out: &mut W) {
let n: u64 = scan.token();
fn solve<W: std::io::Write>(scan: &[u8], out: &mut W) {
let n = u64::to_posint(&scan[..scan.len() - 1]);

let mut low = 1;
let median = (n * n + 1) >> 1;
Expand Down Expand Up @@ -102,19 +86,19 @@ fn solve<W: std::io::Write>(mut scan: UnsafeScanner, out: &mut W) {
// entrypoints //

fn main() {
let scan = UnsafeScanner::new(std::io::stdin());
let mut out = std::io::BufWriter::new(std::io::stdout().lock());
solve(scan, &mut out);
let mut buf_str = vec![];
std::io::stdin().lock().read_to_end(&mut buf_str).unwrap();
let mut out = std::io::stdout().lock();
solve(&buf_str, &mut out);
}

#[cfg(test)]
mod test {
use super::*;

fn test(input: &[u8], target: &[u8]) {
let scan = UnsafeScanner::new(input);
let mut out = Vec::with_capacity(target.len());
solve(scan, &mut out);
solve(input, &mut out);

assert_eq!(out, target);
}
Expand Down
76 changes: 32 additions & 44 deletions src/bin/dynamic_book_shop.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
// I/O boilerplate //

pub struct UnsafeScanner<'a> {
// not actually dead code, needed for buf_iter to work
#[allow(dead_code)]
buf_str: Vec<u8>,
buf_iter: std::str::SplitAsciiWhitespace<'a>,
}
use std::io::Read;

impl UnsafeScanner<'_> {
pub fn new<R: std::io::Read>(mut reader: R) -> Self {
let mut buf_str = vec![];
unsafe {
reader.read_to_end(&mut buf_str).unwrap_unchecked();
}
let buf_iter = unsafe {
let slice = std::str::from_utf8_unchecked(&buf_str);
std::mem::transmute::<
std::str::SplitAsciiWhitespace<'_>,
std::str::SplitAsciiWhitespace<'_>,
>(slice.split_ascii_whitespace())
};

Self { buf_str, buf_iter }
}
pub trait PosInt {
fn to_posint(buf: &[u8]) -> Self;
}

/// Use "turbofish" syntax `token::<T>()` to select data type of next token.
///
/// # Panics
/// Panics if there are no more tokens or if the token cannot be parsed as T.
pub fn token<T: std::str::FromStr>(&mut self) -> T {
unsafe {
self.buf_iter
.next()
.unwrap_unchecked()
.parse()
.unwrap_unchecked()
}
macro_rules! impl_int {
(for $($t:ty),+) => {
$(impl PosInt for $t {
#[allow(clippy::cast_lossless, clippy::cast_possible_wrap)]
fn to_posint(buf: &[u8]) -> Self {
unsafe {
buf.iter()
.map(|byte| (byte & 15) as $t)
.reduce(|acc, digit| acc * 10 + digit)
.unwrap_unchecked()
}
}
})*
}
}
impl_int!(for u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

// problem //

Expand All @@ -64,16 +48,20 @@ impl UnsafeScanner<'_> {
/// <li>1 ≤ x ≤ 10<sup>5</sup></li>
/// <li>1 ≤ h<sub>i</sub>,s<sub>i</sub> ≤ 10<sup>6</sup></li>
/// </ul>
fn solve<W: std::io::Write>(mut scan: UnsafeScanner, out: &mut W) {
let n: u16 = scan.token();
let max_price: usize = scan.token();
fn solve<W: std::io::Write>(scan: &[u8], out: &mut W) {
let mut iter = scan.split(|n| *n <= b' ');

let n = unsafe { u16::to_posint(iter.next().unwrap_unchecked()) };
let max_price = unsafe { usize::to_posint(iter.next().unwrap_unchecked()) };

let prices: Vec<usize> = (0..n).map(|_| scan.token()).collect();
let prices: Vec<usize> = (0..n)
.map(|_| unsafe { usize::to_posint(iter.next().unwrap_unchecked()) })
.collect();

let mut cache = vec![0; max_price + 1];

for price in prices {
let page: u32 = scan.token();
let page = unsafe { u32::to_posint(iter.next().unwrap_unchecked()) };
let mut cache_cp = cache.as_mut_slice();
while cache_cp.len() > price {
let (left, right) = cache_cp.split_at_mut(price);
Expand All @@ -90,19 +78,19 @@ fn solve<W: std::io::Write>(mut scan: UnsafeScanner, out: &mut W) {
// entrypoints //

fn main() {
let scan = UnsafeScanner::new(std::io::stdin());
let mut out = std::io::BufWriter::new(std::io::stdout().lock());
solve(scan, &mut out);
let mut buf_str = vec![];
std::io::stdin().lock().read_to_end(&mut buf_str).unwrap();
let mut out = std::io::stdout().lock();
solve(&buf_str, &mut out);
}

#[cfg(test)]
mod test {
use super::*;

fn test(input: &[u8], target: &[u8]) {
let scan = UnsafeScanner::new(input);
let mut out = Vec::with_capacity(target.len());
solve(scan, &mut out);
solve(input, &mut out);

assert_eq!(out, target);
}
Expand Down
74 changes: 31 additions & 43 deletions src/bin/dynamic_coin_combinations_1.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
// I/O boilerplate //

pub struct UnsafeScanner<'a> {
// not actually dead code, needed for buf_iter to work
#[allow(dead_code)]
buf_str: Vec<u8>,
buf_iter: std::str::SplitAsciiWhitespace<'a>,
}
use std::io::Read;

impl UnsafeScanner<'_> {
pub fn new<R: std::io::Read>(mut reader: R) -> Self {
let mut buf_str = vec![];
unsafe {
reader.read_to_end(&mut buf_str).unwrap_unchecked();
}
let buf_iter = unsafe {
let slice = std::str::from_utf8_unchecked(&buf_str);
std::mem::transmute::<
std::str::SplitAsciiWhitespace<'_>,
std::str::SplitAsciiWhitespace<'_>,
>(slice.split_ascii_whitespace())
};

Self { buf_str, buf_iter }
}
pub trait PosInt {
fn to_posint(buf: &[u8]) -> Self;
}

/// Use "turbofish" syntax `token::<T>()` to select data type of next token.
///
/// # Panics
/// Panics if there are no more tokens or if the token cannot be parsed as T.
pub fn token<T: std::str::FromStr>(&mut self) -> T {
unsafe {
self.buf_iter
.next()
.unwrap_unchecked()
.parse()
.unwrap_unchecked()
}
macro_rules! impl_int {
(for $($t:ty),+) => {
$(impl PosInt for $t {
#[allow(clippy::cast_lossless, clippy::cast_possible_wrap)]
fn to_posint(buf: &[u8]) -> Self {
unsafe {
buf.iter()
.map(|byte| (byte & 15) as $t)
.reduce(|acc, digit| acc * 10 + digit)
.unwrap_unchecked()
}
}
})*
}
}
impl_int!(for u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

// problem //

Expand Down Expand Up @@ -74,10 +58,14 @@ const MODULO: u64 = 1_000_000_007;
/// <li>1 ≤ x ≤ 10<sup>6</sup></li>
/// <li>1 ≤ c<sub>i</sub> ≤ 10<sup>6</sup></li>
/// </ul>
fn solve<W: std::io::Write>(mut scan: UnsafeScanner, out: &mut W) {
let capacity: u8 = scan.token();
let target: usize = scan.token();
let mut coins: Vec<usize> = (0..capacity).map(|_| scan.token::<usize>()).collect();
fn solve<W: std::io::Write>(scan: &[u8], out: &mut W) {
let mut iter = scan.split(|n| *n <= b' ');

let capacity = unsafe { u8::to_posint(iter.next().unwrap_unchecked()) };
let target = unsafe { usize::to_posint(iter.next().unwrap_unchecked()) };
let mut coins: Vec<usize> = (0..capacity)
.map(|_| unsafe { usize::to_posint(iter.next().unwrap_unchecked()) })
.collect();
coins.sort_unstable_by(|a, b| b.cmp(a));
let mut cache = vec![0_u64; target + 1];
cache[0] = 1;
Expand All @@ -97,19 +85,19 @@ fn solve<W: std::io::Write>(mut scan: UnsafeScanner, out: &mut W) {
// entrypoints //

fn main() {
let scan = UnsafeScanner::new(std::io::stdin());
let mut out = std::io::BufWriter::new(std::io::stdout().lock());
solve(scan, &mut out);
let mut buf_str = vec![];
std::io::stdin().lock().read_to_end(&mut buf_str).unwrap();
let mut out = std::io::stdout().lock();
solve(&buf_str, &mut out);
}

#[cfg(test)]
mod test {
use super::*;

fn test(input: &[u8], target: &[u8]) {
let scan = UnsafeScanner::new(input);
let mut out = Vec::with_capacity(target.len());
solve(scan, &mut out);
solve(input, &mut out);

assert_eq!(out, target);
}
Expand Down
Loading

0 comments on commit beebe96

Please sign in to comment.