ABC032 : AtCoder Beginner Contest 032 の A, B, C, D を解いた。
- A - 高橋君と青木君の好きな数
https://atcoder.jp/contests/abc032/tasks/abc032_a
- 提出: https://atcoder.jp/contests/abc032/submissions/38337555
- N 以上の数を昇順に a と b で試し割りして両方とも割り切れたものを出力する
- B - 高橋君とパスワード
https://atcoder.jp/contests/abc032/tasks/abc032_b
- 提出: https://atcoder.jp/contests/abc032/submissions/38337735
- 長さ K の連続する文字列を先頭から順に得て set などで重複を取り除けば良い
- K の長さを数え間違えて 1WA
- C - 列
https://atcoder.jp/contests/abc032/tasks/abc032_c
- 提出: https://atcoder.jp/contests/abc032/submissions/38337828
S
に0
が含まれるならすべてを掛けても条件を満たすのでN
で良い- そうでないときはしゃくとり法で積が K 以下の間伸ばして長さを答えにとっていけば良い
- D - ナップサック問題
https://atcoder.jp/contests/abc032/tasks/abc032_d
- 提出: https://atcoder.jp/contests/abc032/submissions/38339656
- 制約が複数あり、実質 3 問を解いている状態になる
N <= 30
なら件数が少ないので半分全列挙する- ある重さまでに実現可能な価値の最大値を累積和を求める要領で求めておくと良い
W_i <= 1_000
なら最大のW_i
のN
個を上限とすることで通常のナップサック問題として解ける- ぼくの提出に誤りがあり、 W が大きい
W_i <= 1000
のテストケースがあると TLE になりそう V_i <= 1_000
ならある価値を実現する際の重さの最小値として DP を解き- 最後に
W
以下のもののうち最大のV_i
を求めると良い
use std::collections::BTreeMap; use proconio::input; use superslice::Ext; macro_rules! chmax { ($max_v: expr, $v: expr) => { if $v > $max_v { $max_v = $v; true } else { false } }; } macro_rules! chmin { ($min_v: expr, $v: expr) => { if $v < $min_v { $min_v = $v; true } else { false } }; } fn f(w: usize, vw: &[(usize, usize)]) -> Vec<(usize, usize)> { let n = vw.len(); let mut map = BTreeMap::new(); for bits in 0..1 << n { let mut sum_v = 0_usize; let mut sum_w = 0_usize; for i in 0..n { if ((bits >> i) & 1) == 1 { let (v_i, w_i) = vw[i]; sum_v += v_i; sum_w += w_i; } } if sum_w <= w { let entry = map.entry(sum_w).or_insert(sum_v); *entry = (*entry).max(sum_v); } } let mut res = vec![]; let mut maxv = 0; for (k, v) in map { maxv = v.max(maxv); res.push((k, maxv)); } res } fn main() { input! { n: usize, w: usize, vw: [(usize, usize); n], }; let ans = if n <= 30 { let wv1 = f(w, &vw[0..n / 2]); let wv2 = f(w, &vw[n / 2..n]); let mut ans = 0_usize; for (w1, v1) in wv1 { let i = wv2 .lower_bound_by_key(&(w + 1 - w1), |(w2, _)| *w2) .saturating_sub(1); if i < wv2.len() { let (w2, v2) = wv2[i]; if w1 + w2 <= w { ans = ans.max(v1 + v2); } } } ans } else if vw.iter().copied().all(|(_, w_i)| w_i <= 1_000) { let mut dp = vec![0_usize; w + 1]; for (v_i, w_i) in vw { let mut next = vec![0_usize; w + 1]; for j in 0..=w { chmax!(next[j], dp[j]); if j + w_i <= w { chmax!(next[j + w_i], dp[j] + v_i); } } dp = next; } *dp.iter().max().unwrap() } else if vw.iter().copied().all(|(v, _)| v <= 1_000) { let inf = 1 << 60; let mut dp = vec![inf; 1_000 * n + 1]; dp[0] = 0_usize; for (v_i, w_i) in vw { let mut next = vec![inf; 1_000 * n + 1]; next[0] = 0_usize; for j in 0..=1_000 * n { chmin!(next[j], dp[j]); if j + v_i <= 1_000 * n { chmin!(next[j + v_i], dp[j] + w_i); } } dp = next; } dp.into_iter() .enumerate() .filter(|&(_, w_i)| w_i <= w) .map(|(v, _)| v) .max() .unwrap_or(0) } else { unreachable!() }; println!("{}", ans); }
今日のコミット。
- rust-atcoder 1 commit
- rust-sandbox 1 commit