結果
| 問題 | No.3329 Only the Rightest Choice is Right!!! |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-10-25 11:58:56 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
AC
|
| 実行時間 | 138 ms / 1,571 ms |
| コード長 | 3,114 bytes |
| コンパイル時間 | 12,561 ms |
| コンパイル使用メモリ | 400,240 KB |
| 実行使用メモリ | 142,848 KB |
| 最終ジャッジ日時 | 2025-11-02 16:31:50 |
| 合計ジャッジ時間 | 19,077 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 74 |
コンパイルメッセージ
warning: variable `N` should have a snake case name --> src/main.rs:7:9 | 7 | N: usize, | ^ help: convert the identifier to snake case: `n` | = note: `#[warn(non_snake_case)]` on by default warning: variable `W` should have a snake case name --> src/main.rs:8:9 | 8 | W: usize, | ^ help: convert the identifier to snake case (notice the capitalization): `w` warning: variable `N` should have a snake case name --> src/main.rs:34:5 | 34 | N: usize, | ^ help: convert the identifier to snake case: `n` warning: variable `W` should have a snake case name --> src/main.rs:35:5 | 35 | W: usize, | ^ help: convert the identifier to snake case (notice the capitalization): `w`
ソースコード
use proconio::{input, fastout};
#[fastout]
fn main() {
// 入力読み取り
input! {
N: usize,
W: usize,
v: [u32; N],
w: [usize; N],
}
// 動的計画法を実行して選ばれたアイテムの 1-based インデックス列を得る
let ans = solve(N, W, &v, &w);
// 出力(件数とインデックス列)
println!("{}", ans.len());
if !ans.is_empty() {
// Vec<String> に変換してスペース区切りで出力
let s = ans.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" ");
println!("{}", s);
} else {
println!();
}
}
// アルゴリズム本体
// - N: アイテム数
// - W: 重量上限(予算)
// - v: 利益配列(u32)
// - w: 重み配列(usize)
// 戻り値: 選ばれたアイテムの 1-based インデックス列
fn solve(
N: usize,
W: usize,
v: &[u32],
w: &[usize],
) -> Vec<u32> {
// dp[i][j] = (最大利益, 次に進むためのインデックス)
// 次インデックスは選択時に i+1 を格納してあり、選択が無ければ sentinel (usize::MAX)
let sentinel = usize::MAX;
// 初期化: サイズ (N+1) x (W+1)、すべて (0, sentinel)
let mut dp: Vec<Vec<(u64, usize)>> = vec![vec![(0u64, sentinel); W + 1]; N + 1];
// 後ろから遡って DP を構築
for i in (0..N).rev() {
let wi = w[i];
let vi = v[i] as u64;
// j < w[i] の場合は選べないのでそのままコピー
for j in 0..wi.min(W + 1) {
dp[i][j] = dp[i + 1][j];
}
// j >= w[i] の場合は選ぶか選ばないか比較
for j in wi..=W {
let without = dp[i + 1][j].0;
let with = dp[i + 1][j - wi].0 + vi;
// ご利益が等しいなら選ばない方が良い
if without >= with {
dp[i][j] = dp[i + 1][j];
} else {
// 選ぶ場合は利益と「次に進むインデックス」を格納(1-based 相当で i+1)
dp[i][j] = (with, i + 1);
}
}
}
// トレースバック(遡及)パート
let mut ans: Vec<u32> = Vec::new();
let mut idx = dp[0][W].1; // ここには選択された最初のインデックス (i+1) が入るか sentinel
let mut budget = W;
while idx != sentinel {
// dp に格納されている値は i+1(1-based 相当)なのでそのまま出力配列に追加
// 型を u32 に合わせて変換
ans.push(idx as u32);
// 次の budget は現在選んだ要素の重みを引く(w は 0-based、かつ idx は i+1 なので idx-1 が元の i)
let prev_i = idx - 1;
// safety: prev_i は必ず N 未満であるはず(dp の構築論理に基づく)
budget = budget.saturating_sub(w[prev_i]);
// 次の idx を dp テーブルから取得(次の状態は dp[idx][budget].1)
// dp の行インデックスは idx(i+1)でそのまま使える
idx = dp[idx][budget].1;
}
ans
}