結果
問題 | No.2167 Fibonacci Knapsack |
ユーザー |
|
提出日時 | 2023-03-28 23:24:58 |
言語 | Rust (1.83.0 + proconio) |
結果 |
WA
|
実行時間 | - |
コード長 | 4,218 bytes |
コンパイル時間 | 11,904 ms |
コンパイル使用メモリ | 377,752 KB |
実行使用メモリ | 5,376 KB |
最終ジャッジ日時 | 2024-09-20 11:52:35 |
合計ジャッジ時間 | 12,932 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | WA * 21 |
ソースコード
use std::cmp::*;use std::io::{Write, BufWriter};// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8macro_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, [ $t:tt ]) => {{let len = read_value!($next, usize);read_value!($next, [$t; len])}};($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error"));}fn main() {// In order to avoid potential stack overflow, spawn a new thread.let stack_size = 104_857_600; // 100 MBlet thd = std::thread::Builder::new().stack_size(stack_size);thd.spawn(|| solve()).unwrap().join().unwrap();}fn rec(lim: i64, a: &[i64], fib: &[i64]) -> i64 {assert!(lim >= 0);let n = a.len();if n <= 0 {return 0;}if n == 1 {return if lim >= a[0] { fib[0] } else { 0 };}if a[n - 1] + a[n - 2] <= lim {return rec(lim - a[n - 1], &a[..n - 1], fib) + fib[n - 1];}if a[n - 1] > lim {return rec(lim, &a[..n - 1], fib);}if a[n - 2] > lim {return fib[n - 1] + rec(lim - a[n - 1], &a[..n - 2], fib);}if n == 2 {return fib[1];}if n == 3 {let mut ans = fib[n - 1]; // 100if a[n - 1] + a[n - 3] <= lim {ans = max(ans, fib[n - 1] + fib[n - 3]); // 101}return ans;}assert!(n >= 4);if a[n - 1] + a[n - 3] + a[n - 4] <= lim {let mut ans = rec(lim - (a[n - 1] + a[n - 3] + a[n - 4]), &a[..n - 4], fib) + fib[n - 1] + fib[n - 2];ans = max(ans, rec(lim - (a[n - 1] + a[n - 3]), &a[..n - 4], fib) + fib[n - 1] + fib[n - 3]);return ans;}let mut ans = rec(lim - min(a[n - 1], a[n - 2] + a[n - 3]), &a[..n - 3], fib) + fib[n - 1];if a[n - 1] + a[n - 3] <= lim {ans = max(ans, rec(lim - (a[n - 1] + a[n - 3]), &a[..n - 4], fib) + fib[n - 1] + fib[n - 3]);}ans}// https://yukicoder.me/problems/no/2167 (3.5)// \sum_{1 <= i <= N} F_i = F_{N+2} - 2 であるため、N と N-1 が同時に取れるのであれば N は必ず取る必要がある。// 片方は取れるが両方は取れない場合、どちらかを取るのが最善。最大の 3 個の取り方は 101, 100, 011, 010 の 4 通りだが、101 > 010 であり (F_N + F_{N-2}> F_{N-1} + \sum_{1 <= i <= N - 3} F_i)、100 と 011 は残りの重さが大きいほうが良いので、実質 2 通り。こうすると再帰のパターン数は 2^{N/3}であることがわかる。// N-3 も考慮に入れると 1011 > 100, 1011 > 011 であることがわかる。よって 1011 が取れるなら 1011, 1010 の 2 通りに再帰し、そうでないなら 1010 と 100or 011 に再帰するのが良い。オーダーは x^4 = x + 1 の唯一の正の根を r ~= 1.221 として O(r^n) である。r^{75} ~= 3.2 * 10^6 なのでこれでよい。fn solve() {let out = std::io::stdout();let mut out = BufWriter::new(out.lock());macro_rules! puts {($($format:tt)*) => (let _ = write!(out,$($format)*););}input! {t: usize,cs: [([i64], i64); t],}let mut fib = vec![1, 2];while fib.len() < 75 {let tmp = fib[fib.len() - 1] + fib[fib.len() - 2];fib.push(tmp);}for (mut cs, app) in cs {let lim = cs[0];cs.remove(0);cs.push(app);puts!("{}\n", rec(lim, &cs, &fib));}}