結果

問題 No.5005 3-SAT
ユーザー Tekyla
提出日時 2025-12-30 19:43:19
言語 Rust
(1.92.0 + proconio + num)
結果
AC  
実行時間 1,971 ms / 2,000 ms
コード長 22,407 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 14,236 ms
コンパイル使用メモリ 397,940 KB
実行使用メモリ 7,848 KB
スコア 84,519
最終ジャッジ日時 2025-12-30 19:46:55
合計ジャッジ時間 215,480 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: unexpected `cfg` condition value: `local`
   --> src/main.rs:264:15
    |
264 |         #[cfg(feature = "local")]
    |               ^^^^^^^^^^^^^^^^^ help: remove the condition
    |
    = note: no expected values for `feature`
    = help: consider adding `local` as a feature in `Cargo.toml`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default

warning: unexpected `cfg` condition value: `local`
   --> src/main.rs:268:19
    |
268 |         #[cfg(not(feature = "local"))]
    |                   ^^^^^^^^^^^^^^^^^ help: remove the condition
    |
    = note: no expected values for `feature`
    = help: consider adding `local` as a feature in `Cargo.toml`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration

ソースコード

diff #
raw source code

#![allow(unused)]

use proconio::input;

// N:文字列の長さ, M:節の数
const N: usize = 256;
//const N: usize = 24;
const M: usize = 2048;

// two sat を librarycheckerから引っ張ってくる
pub mod jagged {
    use std::fmt::Debug;
    use std::mem::MaybeUninit;
    use std::ops::{Index, IndexMut};

    // Compressed sparse row format, for static jagged array
    // Provides good locality for graph traversal
    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
    pub struct CSR<T> {
        pub links: Vec<T>,
        head: Vec<u32>,
    }

    impl<T: Clone> CSR<T> {
        pub fn from_pairs(n: usize, pairs: impl Iterator<Item = (u32, T)> + Clone) -> Self {
            let mut head = vec![0u32; n + 1];

            for (u, _) in pairs.clone() {
                debug_assert!(u < n as u32);
                head[u as usize] += 1;
            }
            for i in 0..n {
                head[i + 1] += head[i];
            }
            let mut data: Vec<_> = (0..head[n]).map(|_| MaybeUninit::uninit()).collect();

            for (u, v) in pairs {
                head[u as usize] -= 1;
                data[head[u as usize] as usize] = MaybeUninit::new(v.clone());
            }

            // Rustc is likely to perform in‑place iteration without new allocation.
            // [https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html#impl-FromIterator%3CT%3E-for-Vec%3CT%3E]
            let data = data
                .into_iter()
                .map(|x| unsafe { x.assume_init() })
                .collect();

            CSR { links: data, head }
        }
    }

    impl<T, I> FromIterator<I> for CSR<T>
    where
        I: IntoIterator<Item = T>,
    {
        fn from_iter<J>(iter: J) -> Self
        where
            J: IntoIterator<Item = I>,
        {
            let mut data = vec![];
            let mut head = vec![];
            head.push(0);

            let mut cnt = 0;
            for row in iter {
                data.extend(row.into_iter().inspect(|_| cnt += 1));
                head.push(cnt);
            }
            CSR { links: data, head }
        }
    }

    impl<T> CSR<T> {
        pub fn len(&self) -> usize {
            self.head.len() - 1
        }

        pub fn edge_range(&self, index: usize) -> std::ops::Range<usize> {
            self.head[index] as usize..self.head[index as usize + 1] as usize
        }
    }

    impl<T> Index<usize> for CSR<T> {
        type Output = [T];

        fn index(&self, index: usize) -> &Self::Output {
            &self.links[self.edge_range(index)]
        }
    }

    impl<T> IndexMut<usize> for CSR<T> {
        fn index_mut(&mut self, index: usize) -> &mut Self::Output {
            let es = self.edge_range(index);
            &mut self.links[es]
        }
    }

    impl<T> Debug for CSR<T>
    where
        T: Debug,
    {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            let v: Vec<Vec<&T>> = (0..self.len()).map(|i| self[i].iter().collect()).collect();
            v.fmt(f)
        }
    }
}

fn gen_scc(children: &jagged::CSR<u32>) -> (usize, Vec<u32>) {
    // Tarjan algorithm, iterative
    let n = children.len();

    const UNSET: u32 = !0;
    let mut scc_index = vec![UNSET; n];
    let mut n_scc = 0;

    // Stackless DFS
    let mut parent = vec![UNSET; n];
    let mut current_edge: Vec<_> = (0..n)
        .map(|u| children.edge_range(u).start as u32)
        .collect();
    let mut t_in = vec![0u32; n];
    let mut timer = 1;

    let mut low_link = vec![UNSET; n];
    let mut path_stack = vec![];

    for mut u in 0..n as u32 {
        if t_in[u as usize] > 0 {
            continue;
        }

        parent[u as usize] = u;
        loop {
            let e = current_edge[u as usize];
            current_edge[u as usize] += 1;

            if e == children.edge_range(u as usize).start as u32 {
                // On enter
                t_in[u as usize] = timer;
                low_link[u as usize] = timer;
                timer += 1;
                path_stack.push(u);
            }

            if e < children.edge_range(u as usize).end as u32 {
                let v = children.links[e as usize];
                if t_in[v as usize] == 0 {
                    // Front edge
                    parent[v as usize] = u;

                    u = v;
                } else if scc_index[v as usize] == UNSET {
                    // Back edge or cross edge, scc not constructed yet
                    low_link[u as usize] = low_link[u as usize].min(t_in[v as usize]);
                }
            } else {
                // On exit
                if low_link[u as usize] == t_in[u as usize] {
                    // Found a scc
                    loop {
                        let v = path_stack.pop().unwrap();
                        scc_index[v as usize] = n_scc;
                        if v == u {
                            break;
                        }
                    }
                    n_scc += 1;
                }

                let p = parent[u as usize];
                if p == u {
                    break;
                }
                low_link[p as usize] = low_link[p as usize].min(low_link[u as usize]);
                u = p;
            }
        }
    }
    (n_scc as usize, scc_index)
}

pub struct TwoSat {
    n_props: usize,
    edges: Vec<(u32, u32)>,
}

impl TwoSat {
    pub fn new(n_props: usize) -> Self {
        Self {
            n_props,
            edges: vec![],
        }
    }

    pub fn add_disj(&mut self, (p, bp): (u32, bool), (q, bq): (u32, bool)) {
        self.edges
            .push((self.prop_to_node((p, !bp)), self.prop_to_node((q, bq))));
        self.edges
            .push((self.prop_to_node((q, !bq)), self.prop_to_node((p, bp))));
    }

    fn prop_to_node(&self, (p, bp): (u32, bool)) -> u32 {
        debug_assert!(p < self.n_props as u32);
        if bp { p } else { self.n_props as u32 + p }
    }

    fn node_to_prop(&self, node: u32) -> (u32, bool) {
        if node < self.n_props as u32 {
            (node, true)
        } else {
            (node - self.n_props as u32, false)
        }
    }

    pub fn solve(&self) -> Option<Vec<bool>> {
        let children = jagged::CSR::from_pairs(self.n_props * 2, self.edges.iter().copied());
        let (n_scc, scc_index) = gen_scc(&children);

        let scc = jagged::CSR::from_pairs(
            n_scc,
            (0..self.n_props * 2).map(|u| (scc_index[u], u as u32)),
        );

        for p in 0..self.n_props as u32 {
            if scc_index[self.prop_to_node((p, true)) as usize]
                == scc_index[self.prop_to_node((p, false)) as usize]
            {
                return None;
            }
        }

        let mut interpretation = vec![2u8; self.n_props];
        for u in 0..n_scc {
            for &i in &scc[u] {
                let (p, v) = self.node_to_prop(i);
                if interpretation[p as usize] != 2u8 {
                    break;
                }
                interpretation[p as usize] = v as u8;
            }
        }
        Some(interpretation.into_iter().map(|x| x != 0).collect())
    }
}

// https://zenn.dev/tipstar0125/articles/245bceec86e40a
struct TimeKeeper {
    t_start: std::time::Instant,
    t_threshold: f64,
}
impl TimeKeeper {
    fn new(t_threshold: f64) -> Self {
        TimeKeeper {
            t_start: std::time::Instant::now(),
            t_threshold,
        }
    }
    #[inline]
    #[allow(non_snake_case)]
    fn isTimeOver(&self) -> bool {
        let elapsed_time = self.t_start.elapsed().as_nanos() as f64 * 1e-9;
        #[cfg(feature = "local")]
        {
            elapsed_time * 0.85 >= self.t_threshold
        }
        #[cfg(not(feature = "local"))]
        {
            elapsed_time >= self.t_threshold
        }
    }
    fn get_elapsed_time(&self) -> f64 {
        self.t_start.elapsed().as_nanos() as f64 * 1e-9
    }
}

// XorShift
// https://gemini.google.com/app/3ddaf2f301e50794?utm_source=app_launcher&utm_medium=owned&utm_campaign=base_all
struct XorShift32 {
    state: u32,
}

impl XorShift32 {
    // 初期シード
    fn new(seed: u32) -> Self {
        XorShift32 { state: seed }
    }
    // 関数を呼び出すコードを、その関数の中身(本体)で直接置き換える
    // 小さい処理を大量に呼び出す場合につけるとよい
    #[inline]
    // 次の乱数を生成
    fn next_u32(&mut self) -> u32 {
        let mut x = self.state;
        x ^= x << 13;
        x ^= x >> 17;
        x ^= x << 5;
        self.state = x;
        x
    }
    //
    fn next_bool_u8(&mut self) -> u8 {
        (self.next_u32() & 1) as u8
    }
}

// ランダムに0,1 を256個出力する
fn generate_arr(rng: &mut XorShift32) -> [u8; N] {
    let mut res = [0_u8; N];
    for i in 0..N {
        res[i] = rng.next_bool_u8();
    }
    res
}

// 後ろの制約から決めていく
fn generate_arr2(
    rng: &mut XorShift32,
    constraint: &Vec<(usize, usize, usize, u8, u8, u8)>,
) -> [u8; N] {
    let mut res = [0_u8; N];
    for i in (0..M).rev() {
        let &(a, b, c, p, q, r) = &constraint[i];
        let random = rng.next_u32();
        match random % 3 {
            0 => res[a] = p,
            1 => res[b] = q,
            2 => res[c] = r,
            _ => unreachable!(),
        }
    }
    res
}

// スコア計算
fn calc_score(arr: &[u8; N], constraint: &Vec<(usize, usize, usize, u8, u8, u8)>) -> u32 {
    for i in 0..M {
        let &(a, b, c, p, q, r) = &constraint[i];
        if (arr[a] != p) & (arr[b] != q) & (arr[c] != r) {
            return i as u32;
        }
    }
    M as u32
}

// solver_dfc
// 普通に深さ優先探索するとどうなる?
fn dfs(
    arr: &mut [u8; N],
    constraint: &Vec<(usize, usize, usize, u8, u8, u8)>,
    i: usize,
    rng: &mut XorShift32,
    timer: &TimeKeeper,
) -> (u32, [u8; N]) {
    let mut best_score: u32 = i as u32;
    let mut best_arr: [u8; N] = *arr;
    if timer.isTimeOver() || (i >= M) {
        return (best_score, best_arr);
    }
    let &(a, b, c, p, q, r) = &constraint[i];
    // すでに条件達成済み
    if (arr[a] == p) || (arr[b] == q) || (arr[c] == r) {
        return dfs(arr, &constraint, i + 1, rng, &timer);
    } else {
        // ここから条件を動かす
        if arr[a] == 2 {
            arr[a] = p;
            let (score_tmp, arr_tmp) = dfs(arr, constraint, i + 1, rng, timer);
            if score_tmp > best_score {
                best_score = score_tmp;
                best_arr = arr_tmp;
            }
            arr[a] = 2;
        }
        if arr[b] == 2 {
            if timer.isTimeOver() {
                return (best_score, best_arr);
            }
            arr[b] = q;
            let (score_tmp, arr_tmp) = dfs(arr, constraint, i + 1, rng, timer);
            if score_tmp > best_score {
                best_score = score_tmp;
                best_arr = arr_tmp;
            }
            arr[b] = 2;
        }
        if arr[c] == 2 {
            if timer.isTimeOver() {
                return (best_score, best_arr);
            }
            arr[c] = r;
            let (score_tmp, arr_tmp) = dfs(arr, constraint, i + 1, rng, timer);
            if score_tmp > best_score {
                best_score = score_tmp;
                best_arr = arr_tmp;
            }
            arr[c] = 2;
        }
        return (best_score, best_arr);
    }
}

// solver(two-satベース)
fn solver_twosat(
    constraint: &Vec<(usize, usize, usize, u8, u8, u8)>,
    rng: &mut XorShift32,
    timer: &TimeKeeper,
) -> (u32, [u8; N]) {
    // 制約0(0 or 1), 1(0 or 2), 2(1 or 2)
    let mut cnf_list = [0_u8; M];
    for i in 0..M {
        cnf_list[i] = (rng.next_u32() % 3) as u8;
    }
    // 初期cnf_listでokの範囲をにぶたん
    let mut ok = 0_usize;
    let mut ng = M;
    let mut result: Vec<bool> = vec![];
    while ng - ok > 1 {
        let mid = (ok + ng) / 2;
        let mut two_sat = TwoSat::new(N);
        for i in 0..=mid {
            let &(a, b, c, p, q, r) = &constraint[i];
            match cnf_list[i] {
                0 => two_sat.add_disj((a as u32, p == 0), (b as u32, q == 0)),
                1 => two_sat.add_disj((a as u32, p == 0), (c as u32, r == 0)),
                2 => two_sat.add_disj((b as u32, q == 0), (c as u32, r == 0)),
                _ => unreachable!(),
            }
        }
        if let Some(result_binary_search) = two_sat.solve() {
            ok = mid;
            result = result_binary_search;
        } else {
            ng = mid;
        }
    }
    // ここから時間いっぱい頑張る

    while !timer.isTimeOver() {
        // cnf_list の更新
        for i in 0..=(ok + 2).min(M - 1) {
            let &(a, b, c, p, q, r) = &constraint[i];
            let cnf_rng = (rng.next_u32() % 3) as u8;
            let mut change_flag = false;
            if cnf_rng == 0 {
                if (result[a] == (p == 0)) || (result[b] == (q == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else if cnf_rng == 1 {
                if (result[a] == (p == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else {
                if (result[b] == (q == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            }
            // cnf_+1を回す
            if change_flag {
                continue;
            }
            let cnf_rng = (cnf_rng + 1) % 3;
            if cnf_rng == 0 {
                if (result[a] == (p == 0)) || (result[b] == (q == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else if cnf_rng == 1 {
                if (result[a] == (p == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else {
                if (result[b] == (q == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            }
        }
        // two_satを解く
        for ok_i in (ok + 1)..M {
            let mut two_sat = TwoSat::new(N);
            for i in 0..=ok_i {
                let &(a, b, c, p, q, r) = &constraint[i];
                match cnf_list[i] {
                    0 => two_sat.add_disj((a as u32, p == 0), (b as u32, q == 0)),
                    1 => two_sat.add_disj((a as u32, p == 0), (c as u32, r == 0)),
                    2 => two_sat.add_disj((b as u32, q == 0), (c as u32, r == 0)),
                    _ => unreachable!(),
                }
            }
            if let Some(result_tmp) = two_sat.solve() {
                result = result_tmp;
                ok = ok_i;
            } else {
                break;
            }
        }
    }
    let mut ans = [0; N];
    for i in 0..N {
        if !result[i] {
            ans[i] = 1_u8;
        }
    }
    return (ok as u32, ans);
}


fn create_init_cnf_list(constraint: &Vec<(usize, usize, usize, u8, u8, u8)>, limit:usize) -> [u8;M]{
    // 全部は無謀なので、limit までをなるべく満たすようなcnfを探してみる
    let mut counter = [0; N];
    for i in 0..limit.min(M){
        let &(a,b,c,p,q,r) = &constraint[i];
        counter[a] += (p as i32)*2 - 1;
        counter[b] += (q as i32)*2 - 1;
        counter[c] += (r as i32)*2 - 1;
    }
    // なるべく候補が多いやつを選ぶ
    let mut cnf_list = [0_u8; M];
    for i in 0..limit.min(M) {
        let &(a,b,c,p,q,r) = &constraint[i];
        let ai = counter[a] * (2*p as i32-1);
        let bi = counter[b] * (2*q as i32-1);
        let ci = counter[c] * (2*r as i32-1);
        if ai >= bi {
            if bi >= ci{
                continue;
            }else{
                cnf_list[i] = 1_u8;
            }
        }else{
            if ai >= ci{
                continue;
            }else{
                cnf_list[i] = 2_u8;
            }
        }
    }
    return cnf_list;
}


// solver2(two-satベース)
fn solver2_twosat(
    constraint: &Vec<(usize, usize, usize, u8, u8, u8)>,
    rng: &mut XorShift32,
    timer: &TimeKeeper,
) -> (u32, [u8; N]) {
    // 1秒間ランダムに、そのあとは頑張る
    // 制約0(0 or 1), 1(0 or 2), 2(1 or 2)
    let mut cnf_list = create_init_cnf_list(&constraint, 1000);
    // 初期cnf_listでokの範囲をにぶたん
    let mut ok = 0_usize;
    let mut ng = M;
    let mut result: Vec<bool> = vec![];
    while ng - ok > 1 {
        let mid = (ok + ng) / 2;
        let mut two_sat = TwoSat::new(N);
        for i in 0..=mid {
            let &(a, b, c, p, q, r) = &constraint[i];
            match cnf_list[i] {
                0 => two_sat.add_disj((a as u32, p == 0), (b as u32, q == 0)),
                1 => two_sat.add_disj((a as u32, p == 0), (c as u32, r == 0)),
                2 => two_sat.add_disj((b as u32, q == 0), (c as u32, r == 0)),
                _ => unreachable!(),
            }
        }
        if let Some(result_binary_search) = two_sat.solve() {
            ok = mid;
            result = result_binary_search;
        } else {
            ng = mid;
        }
    }
    // ここから時間いっぱい頑張る,1秒間はただランダムに、あとは1節ずつ広げていくように

    while !timer.isTimeOver() {
        // cnf_list の更新
        for i in 0..=(ok + 2).min(M - 1) {
            let &(a, b, c, p, q, r) = &constraint[i];
            let cnf_rng = (rng.next_u32() % 3) as u8;
            let mut change_flag = false;
            if cnf_rng == 0 {
                if (result[a] == (p == 0)) || (result[b] == (q == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else if cnf_rng == 1 {
                if (result[a] == (p == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else {
                if (result[b] == (q == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            }
            // cnf_+1を回す
            if change_flag {
                continue;
            }
            let cnf_rng = (cnf_rng + 1) % 3;
            if cnf_rng == 0 {
                if (result[a] == (p == 0)) || (result[b] == (q == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else if cnf_rng == 1 {
                if (result[a] == (p == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            } else {
                if (result[b] == (q == 0)) || (result[c] == (r == 0)) {
                    cnf_list[i] = cnf_rng;
                    change_flag = true;
                }
            }
        }
        // two_satを解く
        for ok_i in (ok + 1)..M {
            let mut two_sat = TwoSat::new(N);
            for i in 0..=ok_i {
                let &(a, b, c, p, q, r) = &constraint[i];
                match cnf_list[i] {
                    0 => two_sat.add_disj((a as u32, p == 0), (b as u32, q == 0)),
                    1 => two_sat.add_disj((a as u32, p == 0), (c as u32, r == 0)),
                    2 => two_sat.add_disj((b as u32, q == 0), (c as u32, r == 0)),
                    _ => unreachable!(),
                }
            }
            if let Some(result_tmp) = two_sat.solve() {
                result = result_tmp;
                ok = ok_i;
                //println!("{}[s], {}", timer.get_elapsed_time(), ok);
            } else {
                break;
            }
        }
        if ok == M - 1 {
            break;
        }
        //1秒経過した場合、次のようなcnfを試す
        if timer.get_elapsed_time() > 1.0 {
            let mut cnf_list_copy = cnf_list.clone();
            let &(a, b, c, p, q, r) = &constraint[ok + 1];
            // なるべく成立させる条件を選ぶ
            let (abc, pqr) = match rng.next_u32() % 3 {
                0 => (a, p),
                1 => (b, q),
                _ => (c, r),
            };
            // 条件を調整する
            for i in 0..=ok {
                let &(aa, bb, cc, pp, qq, rr) = &constraint[i];
                if (aa == abc) && (pp != pqr) {
                    cnf_list_copy[i] = 2;
                } else if (bb == abc) && (qq != pqr) {
                    cnf_list_copy[i] = 1;
                } else if (cc == abc) && (rr != pqr) {
                    cnf_list_copy[i] = 0;
                }
            }
            // two_satを解いてみる
            let mut two_sat = TwoSat::new(N);
            for i in 0..=(ok+1) {
                let &(a, b, c, p, q, r) = &constraint[i];
                match cnf_list_copy[i] {
                    0 => two_sat.add_disj((a as u32, p == 0), (b as u32, q == 0)),
                    1 => two_sat.add_disj((a as u32, p == 0), (c as u32, r == 0)),
                    2 => two_sat.add_disj((b as u32, q == 0), (c as u32, r == 0)),
                    _ => unreachable!(),
                }
            }
            if let Some(result_tmp) = two_sat.solve() {
                result = result_tmp;
                ok += 1;
                cnf_list = cnf_list_copy;
                //println!("{}[s], {}, 新しいやつ", timer.get_elapsed_time(), ok);
            }
        }
    }

    let mut ans = [0; N];
    for i in 0..N {
        if !result[i] {
            ans[i] = 1_u8;
        }
    }
    return (ok as u32, ans);
}

fn main() {
    // タイマー
    let timer = TimeKeeper::new(1.95);
    // 入力
    input! {
        constraint:[(usize, usize, usize, u8,u8,u8);M]
    }

    // 乱数初期化
    let mut rng = XorShift32::new(4869);
    let (best_score, best_arr) = solver2_twosat(&constraint, &mut rng, &timer);
    // 出力
    //eprintln!("{best_score}");
    for &a in best_arr.iter().rev() {
        if a == 2 { print!("0") } else { print!("{a}") }
    }
}
0