-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add yukicoder/1385.rs yukicoder/2455.rs yukicoder/2477.rs
- Loading branch information
Showing
4 changed files
with
311 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 | ||
macro_rules! input { | ||
($($r:tt)*) => { | ||
let stdin = std::io::stdin(); | ||
let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock())); | ||
let mut next = move || -> String{ | ||
bytes.by_ref().map(|r|r.unwrap() as char) | ||
.skip_while(|c|c.is_whitespace()) | ||
.take_while(|c|!c.is_whitespace()) | ||
.collect() | ||
}; | ||
input_inner!{next, $($r)*} | ||
}; | ||
} | ||
|
||
macro_rules! input_inner { | ||
($next:expr) => {}; | ||
($next:expr,) => {}; | ||
($next:expr, $var:ident : $t:tt $($r:tt)*) => { | ||
let $var = read_value!($next, $t); | ||
input_inner!{$next $($r)*} | ||
}; | ||
} | ||
|
||
macro_rules! read_value { | ||
($next:expr, [ $t:tt ; $len:expr ]) => { | ||
(0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>() | ||
}; | ||
($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error")); | ||
} | ||
|
||
/// Complex numbers. | ||
/// Verified by: ATC001-C (http://atc001.contest.atcoder.jp/submissions/1175487) | ||
mod complex { | ||
use std::ops::{Add, Sub, Mul, Neg}; | ||
#[derive(Clone, Copy, Debug)] | ||
pub struct Complex<T = f64> { | ||
pub x: T, | ||
pub y: T, | ||
} | ||
|
||
impl<T> Complex<T> { | ||
pub fn new(x: T, y: T) -> Self { Complex { x: x, y: y } } | ||
} | ||
impl<T> Add for Complex<T> | ||
where T: Add<Output = T> { | ||
type Output = Self; | ||
fn add(self, other: Self) -> Self { | ||
Self::new(self.x + other.x, self.y + other.y) | ||
} | ||
} | ||
impl<T> Sub for Complex<T> | ||
where T: Sub<Output = T> { | ||
type Output = Self; | ||
fn sub(self, other: Self) -> Self { | ||
Self::new(self.x - other.x, self.y - other.y) | ||
} | ||
} | ||
impl<T: Copy> Mul for Complex<T> | ||
where T: Add<Output = T> + | ||
Sub<Output = T> + | ||
Mul<Output = T> { | ||
type Output = Self; | ||
fn mul(self, other: Self) -> Self { | ||
Self::new(self.x * other.x - self.y * other.y, | ||
self.x * other.y + self.y * other.x) | ||
} | ||
} | ||
impl<T: Copy + Neg<Output = T>> Complex<T> { | ||
pub fn conj(self) -> Self { | ||
Self::new(self.x, -self.y) | ||
} | ||
} | ||
} // complex | ||
|
||
// https://yukicoder.me/problems/no/1385 (3) | ||
// 三角形の面積は 点の座標に関する線形関数 + 定数 として表せるので、累積和ができる。 | ||
// 具体的には、複素数 a, b, c に対してこれらを頂点とする三角形の面積は |Im((b-c)conj(a-c))|/2 である。 | ||
// 絶対値の中身は a, b, c が反時計回りに並んでいる時に正。 | ||
// 点列を時計回りに a[0], ..., a[N-1] として、j < k < i のときの a = a[j], b = a[k], c = a[i] としたときの和を計算することにする。 | ||
// p[i] = \sum_{j < k < i} conj(a[j])a[k] が計算できていれば、c = a[i] のときの Im 内部の和は | ||
// (p[i] - conj(a[i]) \sum_{j < i} ja[j] - a[i] \sum_{j<i}(i - j - 1)conj(a[j]) + |a|^2 i(i-1)/2) / 2 である。 | ||
// これの計算のためには q[i] = \sum_{j < i} ja[j] と r[i] = \sum_{j < i} a[j] がわかっていればよく、 | ||
// これらを使うと (p[i] - conj(a[i]) q[i] + a[i]conj(q[j]) - a[i](i-1)conj(r[i]) + |a|^2 i(i-1)/2) / 2 である。 | ||
fn main() { | ||
input! { | ||
n: usize, l: f64, | ||
t: [f64; n], | ||
} | ||
use complex::*; | ||
let mut a = vec![Complex::new(0.0, 0.0); n]; | ||
for i in 0..n { | ||
let angle = std::f64::consts::PI * t[i] * 2.0 / l; | ||
a[i] = Complex::new(angle.cos(), angle.sin()); | ||
} | ||
let mut p = vec![Complex::new(0.0, 0.0); n + 1]; | ||
let mut q = vec![Complex::new(0.0, 0.0); n + 1]; | ||
let mut r = vec![Complex::new(0.0, 0.0); n + 1]; | ||
for i in 0..n { | ||
r[i + 1] = r[i] + a[i]; | ||
q[i + 1] = q[i] + a[i] * Complex::new(i as f64, 0.0); | ||
if i > 0 { | ||
p[i + 1] = p[i] + a[i] * r[i].conj(); | ||
} | ||
} | ||
let mut ans = Complex::new(0.0, 0.0); | ||
for i in 0..n { | ||
ans = ans + p[i] - a[i].conj() * q[i] + a[i] * q[i].conj() | ||
- a[i] * r[i].conj() * Complex::new(i as f64 - 1.0, 0.0); | ||
} | ||
let nn = n as f64; | ||
println!("{}", ans.y * 3.0 / nn / (nn - 1.0) / (nn - 2.0)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
use std::cmp::*; | ||
use std::io::Read; | ||
|
||
fn get_word() -> String { | ||
let stdin = std::io::stdin(); | ||
let mut stdin=stdin.lock(); | ||
let mut u8b: [u8; 1] = [0]; | ||
loop { | ||
let mut buf: Vec<u8> = Vec::with_capacity(16); | ||
loop { | ||
let res = stdin.read(&mut u8b); | ||
if res.unwrap_or(0) == 0 || u8b[0] <= b' ' { | ||
break; | ||
} else { | ||
buf.push(u8b[0]); | ||
} | ||
} | ||
if buf.len() >= 1 { | ||
let ret = String::from_utf8(buf).unwrap(); | ||
return ret; | ||
} | ||
} | ||
} | ||
|
||
fn get<T: std::str::FromStr>() -> T { get_word().parse().ok().unwrap() } | ||
|
||
// If p10 = 10^k, this function returns a k-digit number | ||
// that is obtained as floor(n * 10^?). | ||
fn pick_digits(mut n: i64, p10: i64) -> i64 { | ||
if n < p10 / 10 { | ||
while n < p10 / 10 { | ||
n *= 10; | ||
} | ||
return n; | ||
} | ||
while n >= p10 { | ||
n /= 10; | ||
} | ||
n | ||
} | ||
|
||
fn main() { | ||
let t: i32 = get(); | ||
for _ in 0..t { | ||
let n: i64 = get(); | ||
let k: i64 = get(); | ||
let mut p = 1; | ||
while p <= n { | ||
p *= 10; | ||
} | ||
let mut ans = 0; | ||
while p > 1 { | ||
p /= 10; | ||
// [p, cur) | ||
let cur = pick_digits(k, 10 * p); | ||
let l = p; | ||
let r = min(cur + 1, min(n + 1, if cur > k { cur } else { cur + 1 })); | ||
if l < r { | ||
ans += r - l; | ||
} | ||
} | ||
println!("{}", ans); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
use std::cmp::*; | ||
use std::collections::*; | ||
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 | ||
macro_rules! input { | ||
($($r:tt)*) => { | ||
let stdin = std::io::stdin(); | ||
let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock())); | ||
let mut next = move || -> String{ | ||
bytes.by_ref().map(|r|r.unwrap() as char) | ||
.skip_while(|c|c.is_whitespace()) | ||
.take_while(|c|!c.is_whitespace()) | ||
.collect() | ||
}; | ||
input_inner!{next, $($r)*} | ||
}; | ||
} | ||
|
||
macro_rules! input_inner { | ||
($next:expr) => {}; | ||
($next:expr,) => {}; | ||
($next:expr, $var:ident : $t:tt $($r:tt)*) => { | ||
let $var = read_value!($next, $t); | ||
input_inner!{$next $($r)*} | ||
}; | ||
} | ||
|
||
macro_rules! read_value { | ||
($next:expr, ( $($t:tt),* )) => { ($(read_value!($next, $t)),*) }; | ||
($next:expr, [ $t:tt ; $len:expr ]) => { | ||
(0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>() | ||
}; | ||
($next:expr, usize1) => (read_value!($next, usize) - 1); | ||
($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error")); | ||
} | ||
|
||
fn divide_into_segment_ranges<F: FnMut(usize)>(n: usize, rng: std::ops::Range<usize>, mut f: F) { | ||
assert!(n.is_power_of_two()); | ||
let (mut a, mut b) = (rng.start, rng.end); | ||
a += n - 1; | ||
b += n - 1; | ||
while a < b { | ||
if (a & 1) == 0 { | ||
f(a); | ||
} | ||
if (b & 1) == 0 { | ||
f(b - 1); | ||
} | ||
a = a / 2; | ||
b = (b - 1) / 2; | ||
} | ||
} | ||
|
||
// 範囲に辺を張りたいので、重み 0 の辺を使って ->->-> という流れを作ってそれの上に辺を張ることにする。 | ||
// -> それだと (a, b) に対して複数の c がある場合にうまくいかないので、代わりにセグメント木を使う。 | ||
// Tags: manual-segment-trees | ||
fn main() { | ||
input! { | ||
n: usize, m: usize, | ||
uvw: [(usize1, usize1, i64); m], | ||
k: usize, | ||
abc: [(usize1, usize1, usize1); k], | ||
} | ||
let mut g = vec![vec![]; n]; | ||
for &(u, v, w) in &uvw { | ||
g[u].push((v, w)); | ||
} | ||
let mut offset = vec![0; n + 1]; | ||
for i in 0..n { | ||
g[i].sort(); | ||
offset[i + 1] = offset[i] + g[i].len(); | ||
} | ||
let mut map = vec![HashMap::new(); n]; | ||
for &(a, b, c) in &abc { | ||
if let Ok(idx) = g[b].binary_search_by_key(&c, |x| x.0) { | ||
map[a].entry(b).or_insert(vec![]).push(idx); | ||
} | ||
} | ||
for i in 0..n { | ||
for e in map[i].values_mut() { | ||
e.sort(); | ||
} | ||
} | ||
let m2 = m.next_power_of_two(); | ||
let mut sup = vec![vec![]; 2 * m2]; // segment tree | ||
for i in 0..m2 - 1 { | ||
sup[i].push((2 * i + 1, 0)); | ||
sup[i].push((2 * i + 2, 0)); | ||
} | ||
for a in 0..n { | ||
for i in 0..g[a].len() { | ||
let (b, w) = g[a][i]; | ||
let idx = offset[a] + i; | ||
if let Some(v) = map[a].get(&b) { | ||
if !v.is_empty() { | ||
for i in 0..v.len() - 1 { | ||
divide_into_segment_ranges(m2, offset[b] + v[i] + 1..offset[b] + v[i + 1], |x| sup[m2 + idx - 1].push((x, w))); | ||
} | ||
divide_into_segment_ranges(m2, offset[b]..offset[b] + v[0], |x| sup[m2 + idx - 1].push((x, w))); | ||
divide_into_segment_ranges(m2, offset[b] + v[v.len() - 1] + 1..offset[b + 1], |x| sup[m2 + idx - 1].push((x, w))); | ||
} | ||
} else { | ||
if b == n - 1 { | ||
sup[m2 - 1 + idx].push((2 * m2 - 1, w)); | ||
} else { | ||
divide_into_segment_ranges(m2, offset[b]..offset[b + 1], |x| sup[m2 + idx - 1].push((x, w))); | ||
} | ||
} | ||
} | ||
} | ||
let mut que = BinaryHeap::new(); | ||
for i in 0..g[0].len() { | ||
que.push((Reverse(0), m2 - 1 + i)); | ||
} | ||
const INF: i64 = 1 << 50; | ||
let mut dist = vec![INF; 2 * m2]; | ||
while let Some((Reverse(d), v)) = que.pop() { | ||
if dist[v] <= d { continue; } | ||
dist[v] = d; | ||
for &(w, c) in &sup[v] { | ||
que.push((Reverse(d + c), w)); | ||
} | ||
} | ||
let ans = dist[2 * m2 - 1]; | ||
println!("{}", if ans >= INF { -1 } else { ans }); | ||
} |