Problem:
Score : 600 points

Problem Statement

Given are an integer N and arrays S, T, U, and V, each of length N.
Construct an N×N matrix a that satisfy the following conditions:

a_{i,j} is an integer.

0 \leq a_{i,j} \lt 2^{64}.

If S_{i} = 0, the bitwise AND of the elements in the i-th row is U_{i}.

If S_{i} = 1, the bitwise OR of the elements in the i-th row is U_{i}.

If T_{i} = 0, the bitwise AND of the elements in the i-th column is V_{i}.

If T_{i} = 1, the bitwise OR of the elements in the i-th column is V_{i}.

However, there may be cases where no matrix satisfies the conditions.

Constraints

All values in input are integers.

1 \leq N \leq 500

0 \leq S_{i} \leq 1

0 \leq T_{i} \leq 1

0 \leq U_{i} \lt 2^{64}

0 \leq V_{i} \lt 2^{64}

Input

Input is given from Standard Input in the following format:

N
S_{1} S_{2} ... S_{N}
T_{1} T_{2} ... T_{N}
U_{1} U_{2} ... U_{N}
V_{1} V_{2} ... V_{N}

Output

If there exists a matrix that satisfies the conditions, print one such matrix in the following format:

a_{1,1} ... a_{1,N}
:
a_{N,1} ... a_{N,N}

Note that any matrix satisfying the conditions is accepted.

If no matrix satisfies the conditions, print -1.

Sample Input 1

2
0 1
1 0
1 1
1 0

Sample Output 1

1 1
1 0

In Sample Input 1, we need to find a matrix such that:

the bitwise AND of the elements in the 1-st row is 1;

the bitwise OR of the elements in the 2-nd row is 1;

the bitwise OR of the elements in the 1-st column is 1;

the bitwise AND of the elements in the 2-nd column is 0.

Sample Input 2

2
1 1
1 0
15 15
15 11

Sample Output 2

15 11
15 11

Solution in Rust (1.42.0) (judge verdict: Accepted)

#![allow(unused)]

use itertools::Itertools;
use std::cmp::{min, max};
use std::io::Write;

macro_rules! debug {
    ($($a:expr),*) => {
        eprintln!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);
    }
}

//
// Based on EbTech's Scanner https://stackoverflow.com/q/56449027
//
struct Scanner<'a, R: std::io::BufRead> {
    reader: R,
    buf: String,
    iter: std::str::SplitWhitespace<'a>,
}

impl<'a, R: std::io::BufRead> Scanner<'a, R> {
    fn new(reader: R) -> Self {
        Self { reader, buf: String::new(), iter: "".split_whitespace() }
    }

    fn get<T: std::str::FromStr>(&mut self) -> T {
        if let Some(t) = self.iter.next() {
            return t.parse().ok().expect("Parse error")
        }
        self.buf.clear();
        self.reader.read_line(&mut self.buf).expect("I/O error");
        self.iter = unsafe { std::mem::transmute(self.buf.split_whitespace()) };
        self.get()
    }
}

//==============================================================================
//
// Problem specific code
//
//==============================================================================

fn verify(
    ans: &Vec<Vec<u64>>,
    n: usize,
    ss: &Vec<i32>,
    ts: &Vec<i32>,
    us: &Vec<u64>,
    vs: &Vec<u64>,
) {
    for i in 0..n {
        if ss[i] == 0 {
            if ans[i].iter().fold(!0, |a, &x| a & x) != us[i] {
                panic!();
            }
        } else {
            if ans[i].iter().fold(0, |a, &x| a | x) != us[i] {
                panic!();
            }
        }
    }
    for j in 0..n {
        if ts[j] == 0 {
            if (0..n).map(|i| ans[i][j]).fold(!0, |a, x| a & x) != vs[j] {
                panic!();
            }
        } else {
            if (0..n).map(|i| ans[i][j]).fold(0, |a, x| a | x) != vs[j] {
                panic!();
            }
        }
    }
}

fn solve(
    n: usize, ss: &Vec<i32>, ts: &Vec<i32>, us: &Vec<u64>, vs: &Vec<u64>
) -> Option<Vec<Vec<u64>>> {
    // Start from zeros and set some of them one.
    let mut ans = vec![vec![0; n]; n];

    let mut ras = vec![!0; n]; // Row AND
    let mut ros = vec![0; n]; // Row OR
    let mut cas = vec![!0; n]; // Column AND
    let mut cos = vec![0; n]; // Column OR

    // Set bits that must be one because of the AND conditions.
    for i in 0..n { for j in 0..n {
        ans[i][j] = match (ss[i], ts[j]) {
            (0, 0) => us[i] | vs[j],
            (0, _) => us[i],
            (_, 0) => vs[j],
            _      => 0,
        };
        ras[i] &= ans[i][j];
        ros[i] |= ans[i][j];
        cas[j] &= ans[i][j];
        cos[j] |= ans[i][j];
    }}

    // Unsatisfiable if the previous step fails to satisfy the AND
    // condition, or the row/column-wise OR have extra '1' bits.
    if (0..n).any(|i|
        (ss[i] == 0 && ras[i] != us[i])
        || (ss[i] != 0 && ros[i] | us[i] != us[i])
        || (ts[i] == 0 && cas[i] != vs[i])
        || (ts[i] != 0 && cos[i] | vs[i] != vs[i]))
    {
        return None;
    }

    for i in 0..n {
        // The AND condition is already satisfied
        if ss[i] == 0 {
            continue
        }

        // Bits that need to be set to satisfy the OR condition
        let mut b = us[i] & !ros[i];

        for j in 0..n {
            if b == 0 {
                break;
            }
            if ts[j] == 0 {
                // Calculate the column-wise AND assuming that `ans[i][j] |= b`.
                // If it has extra '1's, set them in `b` and go to next `j`.
                let and = (0..n).fold(!0, |a, i_| {
                    a & (ans[i_][j] | (if i_ == i { b } else { 0 }))
                });
                let extrabits = and & !vs[j];
                ans[i][j] |= b & !extrabits;
                b = extrabits;
            } else {
                // Set bits that does not changes the column-wise OR
                ans[i][j] |= b & vs[j];
                b &= !vs[j];
            }
        }

        // Unsatisfiable if '1' bits remain in `b`
        if b != 0 {
            return None;
        }
    }

    for j in 0..n {
        if ts[j] == 0 {
            continue
        }

        let mut b = vs[j] & !cos[j];

        for i in 0..n {
            if b == 0 {
                break;
            }
            if ss[i] == 0 {
                let and = (0..n).fold(!0, |a, j_| {
                    a & (ans[i][j_] | (if j_ == j { b } else { 0 }))
                });
                let extrabits = and & !us[i];
                ans[i][j] |= b & !extrabits;
                b = extrabits;
            } else {
                ans[i][j] |= b & us[i];
                b &= !us[i];
            }
        }

        if b != 0 {
            return None;
        }
    }

    //verify(&ans, n, &ss, &ts, &us, &vs);
    Some(ans)
}

fn main() -> std::io::Result<()> {
    let sin = std::io::stdin();
    let mut sc = Scanner::new(sin.lock());

    let n = sc.get();
    let ss: Vec<i32> = (0..n).map(|_| sc.get()).collect();
    let ts: Vec<i32> = (0..n).map(|_| sc.get()).collect();
    let us: Vec<u64> = (0..n).map(|_| sc.get()).collect();
    let vs: Vec<u64> = (0..n).map(|_| sc.get()).collect();

    if let Some(ans) = solve(n, &ss, &ts, &us, &vs) {
        for i in 0..n {
            println!("{}", ans[i].iter().join(" "));
        }
    } else {
        println!("-1");
    }

    Ok(())
}