use std::io::prelude::*;
use std::io::stdin;
use std::str::FromStr;

fn main() {
    let n: usize = read();
    let m: usize = read();
    let mut ss = vec![];

    for _ in 0..m {
        let k: usize = read();
        let s: Vec<usize> = (0..k).map(|_| read()).collect();
        ss.push(s);
    }
    let p: Vec<usize> = (0..m).map(|_| read()).collect();

    let mut switchs = vec![];
    let switch = vec![];
    make_switch_pattern(&mut switchs, &switch, n);

    let ans = switchs
        .iter()
        .filter(|switch| {
            ss.iter()
                .zip(p.iter())
                .filter(|(&s, &p_i)| s.iter().filter(|s_i| !switch[**s_i - 1]).count() % 2 == **p_i)
                .count()
                == m
        })
        .count();

    println!("{}", ans);
}

// true: on, false: off
fn make_switch_pattern(switchs: &mut Vec<Vec<bool>>, switch: &Vec<bool>, count: usize) {
    if count == 0 {
        switchs.push(switch.clone());
    } else {
        let mut switch1 = switch.clone();
        switch1.push(true);
        make_switch_pattern(switchs, &switch1, count - 1);
        let mut switch2 = switch.clone();
        switch2.push(false);
        make_switch_pattern(switchs, &switch2, count - 1);
    }
}

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let token: String = stdin
        .lock()
        .bytes()
        .map(|b| b.unwrap() as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().unwrap()
}
