結果
問題 | No.541 3 x N グリッド上のサイクルの個数 |
ユーザー | koba-e964 |
提出日時 | 2022-01-01 22:46:36 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 821 ms / 2,000 ms |
コード長 | 6,372 bytes |
コンパイル時間 | 13,795 ms |
コンパイル使用メモリ | 383,308 KB |
実行使用メモリ | 6,820 KB |
最終ジャッジ日時 | 2024-10-10 16:32:01 |
合計ジャッジ時間 | 39,915 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 36 ms
6,820 KB |
testcase_01 | AC | 35 ms
6,816 KB |
testcase_02 | AC | 42 ms
6,816 KB |
testcase_03 | AC | 42 ms
6,820 KB |
testcase_04 | AC | 50 ms
6,816 KB |
testcase_05 | AC | 43 ms
6,820 KB |
testcase_06 | AC | 50 ms
6,820 KB |
testcase_07 | AC | 49 ms
6,820 KB |
testcase_08 | AC | 58 ms
6,820 KB |
testcase_09 | AC | 355 ms
6,816 KB |
testcase_10 | AC | 365 ms
6,816 KB |
testcase_11 | AC | 355 ms
6,816 KB |
testcase_12 | AC | 365 ms
6,816 KB |
testcase_13 | AC | 364 ms
6,820 KB |
testcase_14 | AC | 374 ms
6,816 KB |
testcase_15 | AC | 355 ms
6,820 KB |
testcase_16 | AC | 366 ms
6,820 KB |
testcase_17 | AC | 366 ms
6,820 KB |
testcase_18 | AC | 375 ms
6,816 KB |
testcase_19 | AC | 706 ms
6,816 KB |
testcase_20 | AC | 692 ms
6,816 KB |
testcase_21 | AC | 692 ms
6,816 KB |
testcase_22 | AC | 818 ms
6,816 KB |
testcase_23 | AC | 821 ms
6,820 KB |
testcase_24 | AC | 815 ms
6,816 KB |
testcase_25 | AC | 808 ms
6,820 KB |
testcase_26 | AC | 805 ms
6,816 KB |
testcase_27 | AC | 793 ms
6,816 KB |
testcase_28 | AC | 799 ms
6,820 KB |
testcase_29 | AC | 50 ms
6,820 KB |
testcase_30 | AC | 60 ms
6,820 KB |
testcase_31 | AC | 60 ms
6,816 KB |
testcase_32 | AC | 66 ms
6,820 KB |
testcase_33 | AC | 50 ms
6,820 KB |
testcase_34 | AC | 59 ms
6,820 KB |
testcase_35 | AC | 59 ms
6,820 KB |
testcase_36 | AC | 68 ms
6,816 KB |
testcase_37 | AC | 60 ms
6,816 KB |
testcase_38 | AC | 68 ms
6,816 KB |
testcase_39 | AC | 68 ms
6,820 KB |
testcase_40 | AC | 370 ms
6,820 KB |
testcase_41 | AC | 376 ms
6,820 KB |
testcase_42 | AC | 383 ms
6,816 KB |
testcase_43 | AC | 381 ms
6,820 KB |
testcase_44 | AC | 362 ms
6,816 KB |
testcase_45 | AC | 367 ms
6,816 KB |
testcase_46 | AC | 365 ms
6,816 KB |
testcase_47 | AC | 372 ms
6,820 KB |
testcase_48 | AC | 362 ms
6,820 KB |
testcase_49 | AC | 375 ms
6,816 KB |
testcase_50 | AC | 375 ms
6,816 KB |
testcase_51 | AC | 806 ms
6,816 KB |
testcase_52 | AC | 817 ms
6,816 KB |
testcase_53 | AC | 814 ms
6,816 KB |
testcase_54 | AC | 811 ms
6,820 KB |
testcase_55 | AC | 799 ms
6,816 KB |
testcase_56 | AC | 809 ms
6,820 KB |
testcase_57 | AC | 794 ms
6,816 KB |
testcase_58 | AC | 785 ms
6,820 KB |
testcase_59 | AC | 789 ms
6,820 KB |
testcase_60 | AC | 805 ms
6,820 KB |
testcase_61 | AC | 795 ms
6,816 KB |
ソースコード
use std::io::Read; fn get_word() -> String { let stdin = std::io::stdin(); let mut stdin=stdin.lock(); let mut u8b: [u8; 1] = [0]; loop { let mut buf: Vec<u8> = Vec::with_capacity(16); loop { let res = stdin.read(&mut u8b); if res.unwrap_or(0) == 0 || u8b[0] <= b' ' { break; } else { buf.push(u8b[0]); } } if buf.len() >= 1 { let ret = String::from_utf8(buf).unwrap(); return ret; } } } #[allow(dead_code)] fn get<T: std::str::FromStr>() -> T { get_word().parse().ok().unwrap() } // Registry. #[derive(Clone, Default, Debug)] struct Reg<T> { a: Vec<T>, inv: std::collections::HashMap<T, usize>, } impl<T: Default> Reg<T> { pub fn new() -> Self { Self::default() } } impl<T: std::hash::Hash + Eq + Clone> Reg<T> { pub fn get(&mut self, t: &T) -> usize { if !self.inv.contains_key(t) { let idx = self.a.len(); self.a.push(t.clone()); self.inv.insert(t.clone(), idx); } self.inv[t] } // init must have distinct elements. pub fn init<F>(&mut self, init: &[T], f: F) -> Vec<Vec<i64>> where F: Fn(T) -> Vec<T> { let mut que = std::collections::VecDeque::new(); for t in init { let idx = self.get(t); que.push_back(idx); } let mut n = self.a.len(); let mut vis = vec![false; n]; let mut to = vec![vec![]; n]; while let Some(v) = que.pop_front() { if vis[v] { continue; } let ans = f(self.a[v].clone()); let mut entries = vec![]; for elem in ans { let idx = self.get(&elem); entries.push(idx); if n <= idx { // A newly created entry. n = self.a.len(); vis.resize(n, false); to.resize(n, vec![]); que.push_back(idx); } } vis[v] = true; to[v] = entries; } let mut ans = vec![vec![0; n]; n]; for i in 0..n { for &e in &to[i] { ans[i][e] += 1; } } ans } } #[derive(Clone, Default, Debug, Hash, Eq, PartialEq)] struct State { back: i32, me: i32, uf: Vec<usize>, conn: i32, } // For each component, the root is always the maximum element. fn uf_naive(uf: &mut [usize], x: usize, y: usize) { if uf[x] == uf[y] { return; } let n = uf.len(); let r = std::cmp::max(uf[x], uf[y]); let other = r ^ uf[x] ^ uf[y]; for i in 0..n { if uf[i] == other { uf[i] = r; } } } fn next(s: State) -> Vec<State> { let mut ans = vec![]; for i in 0..16 { let back = i; for j in 0..8 { let me = j; // Find the degree of each vertex let mut pre = [0; 4]; let mut now = [0; 4]; for k in 0..3 { if (me & 1 << k) != 0 { now[k] += 1; now[k + 1] += 1; } if (s.me & 1 << k) != 0 { pre[k] += 1; pre[k + 1] += 1; } } for k in 0..4 { if (back & 1 << k) != 0 { now[k] += 1; pre[k] += 1; } if (s.back & 1 << k) != 0 { pre[k] += 1; } } if pre.iter().any(|&x| x != 0 && x != 2) { continue; } // Connectedness let mut nuf = vec![0; 8]; for k in 0..4 { nuf[k] = s.uf[k]; nuf[k + 4] = k + 4; } for k in 0..4 { if (back & 1 << k) == 0 { continue; } // union-find uf_naive(&mut nuf, k, k + 4); } for k in 0..3 { if (me & 1 << k) == 0 { continue; } // union-find uf_naive(&mut nuf, k + 4, k + 5); } let mut uf = vec![0; 4]; let mut conn = s.conn; for k in 0..4 { if pre[k] == 2 && nuf[k] == k { conn += 1; } uf[k] = nuf[k + 4] - 4; } if conn <= 1 { ans.push(State { back, me, uf, conn, }); } } } ans } fn squmul(a: &[Vec<i64>], b: &[Vec<i64>], mo: i64) -> Vec<Vec<i64>> { let n = a.len(); let mut ret = vec![vec![0; n]; n]; for i in 0..n { for j in 0..n { for k in 0..n { ret[i][k] += a[i][j] * b[j][k]; ret[i][k] %= mo; } } } ret } fn squpow(a: &[Vec<i64>], mut e: i64, mo: i64) -> Vec<Vec<i64>> { let n = a.len(); let mut sum = vec![vec![0; n]; n]; for i in 0..n { sum[i][i] = 1; } let mut cur = a.to_vec(); while e > 0 { if e % 2 == 1 { sum = squmul(&sum, &cur, mo); } cur = squmul(&cur, &cur, mo); e /= 2; } sum } // https://yukicoder.me/problems/no/541 (4) // 面倒なことで知られる連結性 DP を、行列累乗に変換する。 // 状態としては、着目する列の 1 つ前の横 (2^4 通り)、着目する列の縦 (2^3 通り)、 // 着目する列の連結性、着目する列以前の連結成分の個数 を持てば良い。 // 行列累乗に変換する部分はライブラリを書いた。 // Tags: connectedness-dp fn main() { let n: i64 = get(); let mut reg = Reg::<State>::new(); let mut uf = vec![0; 4]; for i in 0..4 { uf[i] = i; } let init = State { back: 0, me: 0, uf: uf.clone(), conn: 0 }; let term = State { back: 0, me: 0, uf: uf.clone(), conn: 1 }; let mat = reg.init(&[init.clone()], next); eprintln!("M: {} * {}", reg.a.len(), reg.a.len()); let idx1 = reg.get(&init); let idx2 = reg.get(&term); let pw = squpow(&mat, n + 2, 1_000_000_007); println!("{}", pw[idx1][idx2]); }