Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::{io, str::FromStr, f64::consts, cmp::Ordering};
- fn main() {
- let stdin = io::stdin();
- let mut scan = Scanner::new(stdin.lock());
- let objs_cnt = scan.token();
- let dims = scan.token();
- let objs: Vec<_> = (0..objs_cnt)
- .map(|_| {
- let obj: Vec<_> = (0..dims).map(|_| scan.token()).map(|el: i32| el as f64).collect();
- let reduced: f64 = scan.token();
- (obj, reduced)
- })
- .collect();
- let req: Vec<_> = (0..dims)
- .map(|_| scan.token())
- .map(|el: i32| el as f64)
- .collect();
- let dist: Distance = scan.token();
- let kern: Kernel = scan.token();
- let wndw_prod: WindowProducer = scan.token();
- let wndw = wndw_prod.window(scan.token());
- let dist = dist.as_func();
- let kern = kern.as_func();
- let mut dists: Vec<_> = objs.iter()
- .map(|(obj, red)| (dist(obj, &req), *red))
- .collect();
- dists.sort_unstable_by(|(l_dist, _), (r_dist, _)| if l_dist < r_dist {
- Ordering::Less
- } else if r_dist < l_dist {
- Ordering::Greater
- } else {
- if l_dist.is_nan() || r_dist.is_nan() {
- panic!("NaN");
- }
- Ordering::Equal
- });
- let max_dist = match wndw {
- Window::Distance(max_dist) => max_dist,
- Window::Count(count) => if count < dists.len() { dists[count].0 } else { dists.last().unwrap().0 },
- };
- let average = || dists.iter()
- .map(|(_, red)| *red)
- .sum::<f64>() / dists.len() as f64;
- let ans = if max_dist == 0. {
- let (eq_sum, eq_cnt) = objs.iter()
- .filter_map(|(obj, red)| if *obj == req {
- Some(*red)
- } else { None })
- .fold((0., 0), |(acc_sum, acc_cnt), reduced| (acc_sum + reduced, acc_cnt + 1));
- Some((eq_sum, eq_cnt as f64))
- } else {
- dists.iter()
- .copied()
- .map(|(dist, red)| (kern(dist / max_dist), red))
- .fold(None, |acc, (kern_dist, red)| {
- let num = kern_dist * red;
- let den = kern_dist;
- match acc {
- None => Some((num, den)),
- Some((acc_num, acc_den)) => Some((acc_num + num, acc_den + den)),
- }
- })
- }
- .and_then(|(num, den)| if den != 0. { Some(num / den) } else { None })
- .unwrap_or_else(average);
- println!("{ans}");
- }
- #[derive(Debug, Clone, Copy)]
- pub enum Distance
- {
- Euclid,
- Manhattan,
- Chebyshev,
- }
- impl Distance
- {
- fn euclid(lhs: &[f64], rhs: &[f64]) -> f64
- {
- assert_eq!(lhs.len(), rhs.len());
- let squared: f64 = lhs.into_iter()
- .zip(rhs)
- .map(|(l, r)| *l - *r)
- .map(|d| d * d)
- .sum();
- squared.sqrt()
- }
- fn manhattan(lhs: &[f64], rhs: &[f64]) -> f64
- {
- assert_eq!(lhs.len(), rhs.len());
- lhs.into_iter()
- .zip(rhs)
- .map(|(l, r)| *l - *r)
- .map(f64::abs)
- .sum()
- }
- fn chebyshev(lhs: &[f64], rhs: &[f64]) -> f64
- {
- assert_eq!(lhs.len(), rhs.len());
- lhs.into_iter()
- .zip(rhs)
- .map(|(l, r)| *l - *r)
- .map(f64::abs)
- .reduce(f64::max)
- .unwrap()
- }
- pub fn as_func(&self) -> fn(&[f64], &[f64]) -> f64
- {
- match self {
- Distance::Euclid => Self::euclid,
- Distance::Manhattan => Self::manhattan,
- Distance::Chebyshev => Self::chebyshev,
- }
- }
- }
- impl FromStr for Distance
- {
- type Err = String;
- fn from_str(s: &str) -> Result<Self, Self::Err>
- {
- match s {
- "euclidean" => Ok(Distance::Euclid),
- "manhattan" => Ok(Distance::Manhattan),
- "chebyshev" => Ok(Distance::Chebyshev),
- _ => Err(String::from(s)),
- }
- }
- }
- #[derive(Debug, Clone, Copy)]
- pub enum Kernel
- {
- Uniform,
- Triangular,
- Epanechnikov,
- Quartic,
- Triweight,
- Tricube,
- Gaussian,
- Cosine,
- Logistic,
- Sigmoid
- }
- impl Kernel
- {
- fn uniform(x: f64) -> f64
- { Self::guard(x).unwrap_or_else(|_| 0.5) }
- fn triangular(x: f64) -> f64
- { Self::guard(x).unwrap_or_else(|x| 1. - x.abs()) }
- fn epanechnikov(x: f64) -> f64
- { Self::guard(x).unwrap_or_else(|x| { 0.75 * (1. - x * x) }) }
- fn quartic(x: f64) -> f64
- {
- Self::guard(x)
- .unwrap_or_else(|x| {
- let mul = 1. - x * x;
- (15. / 16.) * mul * mul
- })
- }
- fn triweight(x: f64) -> f64
- {
- Self::guard(x)
- .unwrap_or_else(|x| {
- let mul = 1. - x * x;
- (35. / 32.) * mul * mul * mul
- })
- }
- fn tricube(x: f64) -> f64
- {
- Self::guard(x)
- .unwrap_or_else(|x| {
- let x = x.abs();
- let mul = 1. - x * x * x;
- (70. / 81.) * mul * mul * mul
- })
- }
- fn gaussian(x: f64) -> f64
- {
- let e = (-0.5 * x * x).exp();
- let coef = 1. / (consts::PI * 2.).sqrt();
- coef * e
- }
- fn cosine(x: f64) -> f64
- {
- Self::guard(x)
- .unwrap_or_else(|x| {
- let angle = consts::FRAC_PI_2 * x;
- consts::FRAC_PI_4 * angle.cos()
- })
- }
- fn logistic(x: f64) -> f64
- {
- let den = x.exp() + (-x).exp() + 2.;
- 1. / den
- }
- fn sigmoid(x: f64) -> f64
- {
- let den = x.exp() + (-x).exp();
- consts::FRAC_2_PI / den
- }
- fn guard(x: f64) -> Result<f64, f64>
- {
- if x.abs() >= 1. {
- Ok(0.)
- } else {
- Err(x)
- }
- }
- fn as_func(&self) -> fn (f64) -> f64
- {
- match self {
- Kernel::Uniform => Self::uniform,
- Kernel::Triangular => Self::triangular,
- Kernel::Epanechnikov => Self::epanechnikov,
- Kernel::Quartic => Self::quartic,
- Kernel::Triweight => Self::triweight,
- Kernel::Tricube => Self::tricube,
- Kernel::Gaussian => Self::gaussian,
- Kernel::Cosine => Self::cosine,
- Kernel::Logistic => Self::logistic,
- Kernel::Sigmoid => Self::sigmoid,
- }
- }
- }
- impl FromStr for Kernel
- {
- type Err = String;
- fn from_str(s: &str) -> Result<Self, Self::Err>
- {
- match s {
- "uniform" => Ok(Kernel::Uniform),
- "triangular" => Ok(Kernel::Triangular),
- "epanechnikov" => Ok(Kernel::Epanechnikov),
- "quartic" => Ok(Kernel::Quartic),
- "triweight" => Ok(Kernel::Triweight),
- "tricube" => Ok(Kernel::Tricube),
- "gaussian" => Ok(Kernel::Gaussian),
- "cosine" => Ok(Kernel::Cosine),
- "logistic" => Ok(Kernel::Logistic),
- "sigmoid" => Ok(Kernel::Sigmoid),
- _ => Err(String::from(s)),
- }
- }
- }
- #[derive(Debug, Clone, Copy)]
- enum Window
- {
- Distance(f64),
- Count(usize),
- }
- #[derive(Debug, Clone, Copy)]
- enum WindowProducer
- {
- Distance,
- Count,
- }
- impl FromStr for WindowProducer
- {
- type Err = String;
- fn from_str(s: &str) -> Result<Self, Self::Err>
- {
- match s {
- "fixed" => Ok(WindowProducer::Distance),
- "variable" => Ok(WindowProducer::Count),
- _ => Err(String::from(s)),
- }
- }
- }
- impl WindowProducer
- {
- fn window(&self, num: i32) -> Window
- {
- match self {
- WindowProducer::Distance => Window::Distance(num as f64),
- WindowProducer::Count => Window::Count(num as usize),
- }
- }
- }
- struct Scanner<R> {
- reader: R,
- buf_str: Vec<u8>,
- buf_iter: std::str::SplitAsciiWhitespace<'static>,
- }
- impl<R: io::BufRead> Scanner<R> {
- fn new(reader: R) -> Self {
- Self { reader, buf_str: Vec::new(), buf_iter: "".split_ascii_whitespace() }
- }
- fn token<T: FromStr>(&mut self) -> T {
- loop {
- if let Some(token) = self.buf_iter.next() {
- return token.parse().ok().expect("Failed parse");
- }
- self.buf_str.clear();
- self.reader.read_until(b'\n', &mut self.buf_str).expect("Failed read");
- self.buf_iter = unsafe {
- let slice = std::str::from_utf8_unchecked(&self.buf_str);
- std::mem::transmute(slice.split_ascii_whitespace())
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement