AtCoder Beginner Contest 253
AtCoder Beginner Contest 253 です。
A - Median?
$a,b,c$ が与えられるので $b$ が中央値か? と言う問題 a..=c
の間に $b$ が含まれていると良い。
fn main() { input! { a : usize, b : usize, c : usize } println!("{}", if (a.min(c)..=c.max(a)).contains(&b) {"Yes"} else {"No"}); }
B - Distance Between Tokens
'o'
の座標を求めて、x軸方向とy軸方向別々に距離を足したら良い。同じ記号なので少しめんどくさい。
fn main() { input! { h : usize, w : usize, s : [Chars; h] } let mut st = (0,0); let mut g = (0,0); let mut f = false; for i in 0..h { for j in 0..w { if s[i][j] == '-' {continue} if !f { st = (i,j); f=true;} else { g = (i,j); } }} println!("{}", st.0.max(g.0) - st.0.min(g.0) + st.1.max(g.1) - st.1.min(g.1)); }
C - Max - Min Query
$x$ を多重集合に入れたり、 $x$ を $c$ 個多重集合から消したりする(足りなかったら $0$ になるまで)。後、多重集合の max と min を求める。
問題はシンプルだが、データ構造がないとめんどくさい。 BTreeMultiSet を作っているので、それをはっつける。 $c$個削除は実装していなかったので、温かみのある実装をする。
流石に無いのは不便なので、コンテストあとに実装した(修正版)。
fn main() { input! { q : usize } let mut s = BtreeMultiSet::new(); for _ in 0..q { input! { t : u8 } match t { 1 => { input! { x : usize } s.add(x); } 2 => { input! { x : usize, c : usize } match s.set.get_mut(&x) { Some(xc) => { if *xc <= c { s.set.remove(&x); } else { *xc -= c; } } None => {}, } } 3 => { println!("{}", s.last().unwrap() - s.first().unwrap()); } _ => unreachable!() } } }
D - FizzBuzz Sum Hard
$N$ 以下の正整数のうち $A$の倍数でも $B$ の倍数でもないものの総和を求める問題。最初総和じゃなくて個数を求めて 「???」となっていた。
Rust を信じて (0..=n).step_by(a).sum::<usize>()
などとするも TLE。 O(1) でやってくれ……!
仕方ないので、自分で式を書く。
fn main() { input! { n : usize, a : usize, b : usize } let mut ans = n * (n+1) / 2; ans -= (a + n/a*a) * (n/a) / 2; ans += (lcm(a,b) + n/lcm(a,b)*lcm(a,b)) * (n/lcm(a,b)) / 2; ans -= (b + n/b*b) * (n/b) / 2; println!("{}", ans); }
E - Distance Sequence
dp[i][j]
i桁決まって、 $A _ i = j$ である場合の数とかをやれば良い。そのまま計算すると O(NMK) とかになってヤバそうなので、累積和取っておいて、 総和 - 満たさない範囲 とかをしたら良い。 $K = 0$ のときに注意
fn main() { input! { n : usize, m : usize, k : usize } if k == 0 { println!("{}", pow(m,n,MOD as usize)); return; } const MOD : i64 = 998_244_353; let mut dp = vec![1; m+1]; for _ in 1..n { let mut next = vec![0; m+1]; let mut csum = vec![0; m+2]; let mut sum = 0; for i in 1..=m { csum[i] = (csum[i-1] + dp[i]) % MOD; sum += dp[i]; sum %= MOD; } for i in 1..=m { next[i] = (sum + MOD - csum[m.min(i+k-1)] + csum[i.saturating_sub(k)]) % MOD; next[i] %= MOD; } dp = next.into_iter().map(|d| d % MOD).collect_vec(); } let mut ans = dp[1..].iter().fold(0, |acc,&v| (acc+v) % MOD) % MOD; println!("{}", ans); }
F - Operations on a Matrix
本番中解けなかった。クエリ平方分割しようとして沼った。
後半に考えていた、後ろからやって $i$ 行目を $x$ にする操作のときに良い感じに計算するやつ、結局時間が足りずに詰め切れなかったんだけど、コンテスト後にちゃんと書いたら通った。
3 のクエリが流れてきたときを $0$ として、良い感じにやると良い。
fn main() { input! { n : usize, m : usize, q : usize, } let mut queries = Vec::with_capacity(q); let mut bit = FenwickTree::<i64>::new(m+1); let mut cnt = 0; let mut nq = vec![vec![]; n]; for _ in 0..q { input! { t : u8 } match t { 1 => { input! { l:Usize1, r:usize, x:i64 } queries.push((t, l, r, x)); } 2 => { input! { i:Usize1, mut x:i64 } queries.push((t, i, 0, x)); } 3 => { input! { i:Usize1, j:Usize1 } queries.push((t, i, j, cnt)); cnt += 1; } _ => unreachable!() } } let mut ans = vec![0; cnt as usize]; for (t, l, r, x) in queries.into_iter().rev() { match t { 1 => { bit.add(l, x); bit.add(r, -x); } 2 => { let i = l; for (index, j) in nq[i].drain(..) { ans[index as usize] += x + bit.fold(j); } } 3 => { let (i, j) = (l,r); let index = x as usize; nq[i].push((index, j)); ans[index] -= bit.fold(j); } _ => unreachable!() } } for i in 0..n { for (index, i) in nq[i].drain(..) { ans[index as usize] += bit.fold(i); } } println!("{}", ans.iter().join("\n")); }
G - Swap Many Times
見てない。
Ex - We Love Forest
見てない
まとめ
微妙。 レート 1529 → 1530(+1)