結果
問題 |
No.3047 Verification of Sorting Network
|
ユーザー |
👑 |
提出日時 | 2025-02-12 11:56:13 |
言語 | Rust (1.83.0 + proconio) |
結果 |
AC
|
実行時間 | 418 ms / 2,000 ms |
コード長 | 10,021 bytes |
コンパイル時間 | 13,566 ms |
コンパイル使用メモリ | 397,228 KB |
実行使用メモリ | 7,324 KB |
最終ジャッジ日時 | 2025-03-09 23:56:03 |
合計ジャッジ時間 | 28,254 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 61 |
ソースコード
const MAX_T: usize = 10000; const MAX_N: usize = 27; const MAX_COST: f64 = 1e8; //const MAX_T: usize = 100000; //const MAX_N: usize = 64; //const MAX_COST: f64 = 1e11; type NodeIndex = u8; type CmpIndex = usize; type State = u64; const FIB1: [State; State::BITS as usize + 1] = { let mut fib = [0; State::BITS as usize + 1]; fib[0] = 1; fib[1] = 1; let mut i = 2; while i <= State::BITS as _ { fib[i] = fib[i - 1] + fib[i - 2]; i += 1; } fib }; // 与えられた比較交換器ネットワークがソーティングネットワークかどうかをチェック fn is_sorting_network(n: usize, cmp: &[(usize, usize)]) -> Result<Vec<bool>, Vec<bool>> { const { assert!(MAX_N <= NodeIndex::MAX as _ && MAX_N * (MAX_N - 1) / 2 <= CmpIndex::MAX as _) }; assert!(2 <= n && (n as usize) <= MAX_N && n <= State::BITS as _ && n <= NodeIndex::MAX as _); assert!(cmp.len() <= CmpIndex::MAX as _); // 0-indexed かつ a < b かつ b < n であることを確認 assert!(cmp.iter().all(|&(a, b)| a < b && b < n)); // スタックに積む要素: 0状態ベクトル z, 1状態ベクトル o, 比較交換器の番号 i // もし ((z >> j) & 1, (o >> j) & 1) == (1, 1) なら j-bit目の状態は '?' // もし ((z >> j) & 1, (o >> j) & 1) == (1, 0) なら j-bit目の状態は '0' // もし ((z >> j) & 1, (o >> j) & 1) == (0, 1) なら j-bit目の状態は '1' // '0...01...1' または '0...0?1...1' の場合、ソートされている // 初期状態: 0状態ベクトルは[0,n)-bit目が1、1状態ベクトルは全bitが1、比較交換器の番号は 0 struct SearchState { n: usize, unused: Vec<bool>, unsorted: Vec<bool>, progress: State, next_progress: State, } impl SearchState { fn progress_inc(&mut self, x: State) { self.progress += x; if self.progress >= self.next_progress { let percent = self.progress * 100 / FIB1[self.n]; eprint!("\r{}%", percent); self.next_progress = ((percent + 1) * FIB1[self.n] - 1) / 100 + 1; } } fn search(&mut self, cmp: &[(NodeIndex, NodeIndex)], z: State, o: State, i: usize) { if let Some(&(a, b)) = cmp.get(i) { match ((z >> a) & 1, (o >> a) & 1, (z >> b) & 1, (o >> b) & 1) { (1, 0, _, _) | (_, _, 0, 1) => { // 比較交換器の入力が ('0', _) or (_, '1') {_ は任意を示す} の場合、 // 交換はないので次の比較交換器へ進む self.search(cmp, z, o, i + 1); } (1, 1, 1, 1) => { // この比較交換器は使用される可能性あり self.unused[i] = false; // 比較交換器の入力が ('?', '?') であれば、 ('0', '0') と ('?', '1') に分岐して探索 // qz,qo: ('?', '?') -> ('0', '0') let (qz, qo) = (z, o & (!(1 << a) & !(1 << b))); // rz,ro: ('?', '?') -> ('?', '1') let (rz, ro) = (z & !(1 << b), o); // (qz,qo) がソートされていない場合、分岐を調べる if (qz & !qo).trailing_ones() + (qo & !qz).leading_ones() < State::BITS - 1 { self.search(cmp, qz, qo, i + 1); } else { self.progress_inc(1); } // (rz,ro) がソートされていない場合、分岐を調べる if (rz & !ro).trailing_ones() + (ro & !rz).leading_ones() < State::BITS - 1 { self.search(cmp, rz, ro, i + 1); } else { self.progress_inc(1); } } _ => { // この比較交換器は使用される可能性あり self.unused[i] = false; // 比較交換器の入力が ('1', '0') or ('?', '0') or ('1', '?') の場合、要素を交換 let xz = ((z >> a) ^ (z >> b)) & 1; let xo = ((o >> a) ^ (o >> b)) & 1; let qz = z ^ (xz << a | xz << b); let qo = o ^ (xo << a | xo << b); // (rz,ro) がソートされていない場合、分岐を調べる if (qz & !qo).trailing_ones() + (qo & !qz).leading_ones() < State::BITS - 1 { self.search(cmp, qz, qo, i + 1); } else { self.progress_inc(1); } } } } else { for j in 0..State::BITS - 1 { match ( (z >> j) & 1, (o >> j) & 1, (z >> (j + 1)) & 1, (o >> (j + 1)) & 1, ) { // ('0', '0') または ('1', '1') または ('0', '1') または ('0', '?') または ('?', '1') の場合 // 操作なし (1, 0, _, _) | (_, _, 0, 1) => {} // ('?', '?') または ('?', '0') または ('1', '?') または ('1', '0') の場合 // ソートされていないとマーク _ => { self.unsorted[j as usize] = true; } } } self.progress_inc(FIB1[(z & o).count_ones() as usize]); } } } let mut state = SearchState { n, unused: vec![true; cmp.len()], unsorted: vec![false; (n - 1) as _], progress: 0, next_progress: 0, }; state.search( &cmp.iter() .map(|&(a, b)| (a as NodeIndex, b as NodeIndex)) .collect::<Vec<_>>(), State::MAX >> (State::BITS - n as u32), State::MAX, 0, ); eprintln!(); assert!(state.progress == FIB1[n]); // すべての分岐が終了 // いずれかの分岐でソートされていない場合、 unsorted に true が含まれるのでソーティングネットワークではない if state.unsorted.iter().any(|&f| f) { // ソートされていない可能性のある位置を返す Err(state.unsorted) } else { // すべての分岐においてソートされたならばソーティングネットワーク // 未使用の比較交換器を返す Ok(state.unused) } } fn main() -> Result<(), Box<dyn std::error::Error>> { use std::io::Write; let execution_start = std::time::Instant::now(); let stdin = std::io::stdin(); let mut lines = std::io::BufRead::lines(stdin.lock()); let mut bout = std::io::BufWriter::new(std::io::stdout()); let t: usize = lines.next().unwrap()?.trim().parse()?; assert!(t <= MAX_T); // φ = (1 + √5) / 2 : 黄金数 1.618033988749895 let phi = (1.25f64).sqrt() + 0.5; let mut cost = 0f64; for _ in 0..t { let line = lines.next().unwrap()?; let mut parts = line.split_whitespace(); let n: usize = parts.next().unwrap().parse()?; let m: usize = parts.next().unwrap().parse()?; assert!(2 <= n && (n as usize) <= MAX_N); assert!(1 <= m && m <= (n as usize) * ((n as usize) - 1) / 2); cost += m as f64 * phi.powi(n as i32); // テストケースのコスト <= MAX_COST assert!(cost <= MAX_COST); // 比較交換器を読み込む let vec_a = lines .next() .unwrap()? .split_whitespace() .map(|s| s.parse::<usize>().unwrap()) .collect::<Vec<_>>(); let vec_b = lines .next() .unwrap()? .split_whitespace() .map(|s| s.parse::<usize>().unwrap()) .collect::<Vec<_>>(); let cmp = vec_a .iter() .zip(vec_b.iter()) .map(|(&a, &b)| (a - 1, b - 1)) .collect::<Vec<_>>(); // ソーティングネットワークかどうかをチェック match is_sorting_network(n, &cmp) { Ok(unused) => { writeln!(&mut bout, "Yes")?; // 未使用の比較交換器 j を列挙 writeln!(&mut bout, "{}", unused.iter().filter(|&&f| f).count())?; // 1-indexed writeln!( &mut bout, "{}", unused .iter() .enumerate() .filter_map(|(j, &u)| if u { Some((j + 1).to_string()) } else { None }) .collect::<Vec<_>>() .join(" ") )?; } Err(unsorted) => { writeln!(&mut bout, "No")?; // ソートされていない可能性がある位置 k を列挙 writeln!(&mut bout, "{}", unsorted.iter().filter(|&&f| f).count())?; // 1-indexed writeln!( &mut bout, "{}", unsorted .iter() .enumerate() .filter_map(|(k, &u)| if u { Some((k + 1).to_string()) } else { None }) .collect::<Vec<_>>() .join(" ") )?; } } } bout.flush()?; eprintln!("{} ms", execution_start.elapsed().as_millis()); Ok(()) }