fn solve(ksss: Vec<Vec<u64>>, ps: Vec<u64>, n: usize) -> usize {
    let mut result = 0;
    let sss: Vec<Vec<u64>> = ksss.iter()
        .map(|kss| kss.iter().skip(1).map(|s| s - 1).collect::<Vec<_>>())
        .collect();

    for bins in binary_combinations(n) {
        if (0..ps.len()).all(|i| sss[i].iter().zip(&bins).filter(|(_, &bin)| bin).count() % 2 == ps[i] as usize) {
            result += 1
        }
    }

    result
}

fn binary_combinations(n: usize) -> Vec<Vec<bool>> {
    fn rec(n: usize, mut acc: Vec<Vec<bool>>) -> Vec<Vec<bool>> {
        if n == 0 {
            acc
        } else {
            let mut tmp = acc.clone();
            acc.iter_mut().for_each(|v| v.push(false));
            tmp.iter_mut().for_each(|v| v.push(true));
            acc.extend(tmp);

            rec(n - 1, acc)
        }
    }

    rec(n, vec![vec![]])
}

fn main() {
    let (n, m) = read_tup2();
    let ksss = read_vec_n(m);
    let ps = read_vec();

    println!("{}", solve(ksss, ps, n));
}

fn read_tup2<T: std::str::FromStr + Copy>() -> (T, T) {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    let v = s.trim().split_whitespace()
        .map(|c| c.parse().ok().unwrap())
        .collect::<Vec<T>>();
    (v[0], v[1])
}

fn read_vec_n<T: std::str::FromStr>(n: usize) -> Vec<Vec<T>> {
    let mut ss = String::new();
    for _ in 0..n {
        std::io::stdin().read_line(&mut ss).ok();
    }
    let mut v = ss.split("\n").collect::<Vec<&str>>();
    v.pop();
    v.iter()
        .map(
            |s| {
                s.trim().split_whitespace()
                    .map(|c| c.parse().ok().unwrap())
                    .collect()
            }
        )
        .collect()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().split_whitespace()
        .map(|c| c.parse().ok().unwrap())
        .collect()
}
