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 std::io::{Read, Stdin, StdinLock};
use std::iter::{FromIterator, Iterator};
use std::str::{FromStr};
use std::string::String;
use itertools::Itertools;
use std::cmp::{min, max};

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

struct TokenReader<'a> {
    lock: StdinLock<'a>,
}

impl<'a> TokenReader<'a> {
    fn new(s: &'a Stdin) -> TokenReader<'a> {
        TokenReader { lock: s.lock() }
    }

    fn read_chars<T: FromIterator<char>>(&mut self) -> T {
        self.lock
            .by_ref()
            .bytes()
            .map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect::<T>()
    }

    fn read_str(&mut self) -> String {
        self.read_chars::<String>()
    }

    fn read<T: FromStr>(&mut self) -> T {
        self.read_str().parse().ok().unwrap()
    }
}

//==============================================================================
//
// 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];
    let mut ros = vec![0; n];
    let mut cas = vec![!0; n];
    let mut cos = vec![0; n];

    // 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 {
        // AND 条件は既に満たされている
        if ss[i] == 0 {
            continue
        }

        let mut b = us[i] & !ros[i]; // Bits that need to be set
        for j in 0..n {
            if b == 0 {
                break;
            }
            if ts[j] == 0 {
                // 仮に欲しいビットを全部立てたとして，列 AND を計算．
                // 余計なビットが立ってしまったらそのビットだけ除いて次のループへ
                let testand = (0..n).fold(!0, |a, i_| {
                    a & (ans[i_][j] | (if i_ == i { b } else { 0 }))
                });
                let a = testand & !vs[j]; // 立っていてはいけないビット
                assert!(b | a == b); // a は b のサブセット
                ans[i][j] |= b & !a; // 立ててもよいビット
                b = a;
            } else {
                // 列 OR に含まれているビットは全て立ててよい
                ans[i][j] |= b & vs[j];
                b &= !vs[j];
            }
        }

        if b != 0 {
            return None;
        }
    }

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

        let mut b = vs[j] & !cos[j]; // Bits that need to be set
        for i in 0..n {
            if b == 0 {
                break;
            }
            if ss[i] == 0 {
                let testand = (0..n).fold(!0, |a, j_| {
                    a & (ans[i][j_] | (if j_ == j { b } else { 0 }))
                });
                let a = testand & !us[i]; // 立っていてはいけないビット
                assert!(b | a == b); // a は b のサブセット
                ans[i][j] |= b & !a; // 立ててもよいビット
                b = a;
            } else {
                // 列 OR に含まれているビットは全て立ててよい
                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() {
    let sin = std::io::stdin();
    let mut tr = TokenReader::new(&sin);

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

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