//ライブラリ
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>
#include <numeric>
#include <cmath>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <complex>
#include <string.h>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#include <iomanip>
#include <sys/time.h>
#include <tuple>
#include <random>
#include <functional>
using namespace std;

//ユーティリティ
#define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define reps(i,n) for(int i=1, i##_len=(n); i<=i##_len; ++i)
#define rrep(i,n) for(int i=n-1; i>=0; --i)
#define rreps(i,n) for(int i=n; i>0; --i)
#define vmax(v) *max_element(all(v))
#define vmin(v) *min_element(all(v))
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define uniq(v) (v).erase(unique((v).begin(), (v).end()), (v).end())

template<class T>bool chmax(T &former, const T &b) {if (former<b) {former=b;return true;} return false;}
template<class T>bool chmin(T &former, const T &b) {if (former>b) {former=b;return true;} return false;}

//型
//型
typedef long long int ll;
typedef long long unsigned int ull;
typedef pair<int, int> pairi;
typedef pair<ull, ull> pairull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<ull> vull;
typedef priority_queue<int, vi> pq;
typedef priority_queue<int, vi, greater<int>> rpq;

//定数
#define INF (1e9+9)
#define MOD (1e9 + 7);
const double pi = (acos(-1));
const double eps = 1e-8;

//セグメント木
//データ構造
template< typename Monoid >
struct SegmentTree {
    using F = function< Monoid(Monoid, Monoid) >;

    int sz;
    vector< Monoid > seg;

    const F f;
    const Monoid M1;

    SegmentTree(int n, const F f, const Monoid &M1) : f(f), M1(M1) {
        sz = 1;
        while(sz < n) sz <<= 1;
        seg.assign(2 * sz, M1);
    }

    void set(int k, const Monoid &x) {
        seg[k + sz] = x;
    }

    void build() {
        for(int k = sz - 1; k > 0; k--) {
            seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
        }
    }

    void update(int k, const Monoid &x) {
        k += sz;
        seg[k] = x;
        while(k >>= 1) {
            seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
        }
    }

    Monoid query(int a, int b) {
        Monoid L = M1, R = M1;
        for(a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
            if(a & 1) L = f(L, seg[a++]);
            if(b & 1) R = f(seg[--b], R);
        }
        return f(L, R);
    }

    Monoid operator[](const int &k) const {
        return seg[k + sz];
    }
};

//グラフ
template< typename T >
struct edge {
    int src, to;
    T cost;

    edge(int to, T cost) : src(-1), to(to), cost(cost) {}

    edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

    edge &operator=(const int &x) {
        to = x;
        return *this;
    }

    operator int() const { return to; }
};

template< typename T >
using Edges = vector< edge< T > >;
template< typename T >
using WeightedGraph = vector< Edges< T > >;
using UnWeightedGraph = vector< vector< int > >;
template< typename T >
using Matrix = vector< vector< T > >;

template< typename T >
void warshall_floyd(Matrix< T > &g, T inf) {
    for(int k = 0; k < g.size(); k++) {
        for(int i = 0; i < g.size(); i++) {
            for(int j = 0; j < g.size(); j++) {
                if(g[i][k] == inf || g[k][j] == inf) continue;
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
            }
        }
    }
}





/*
// 法の元の演算
// modを維持しながらべき乗。
ll mod_pow(ll x, ll n) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = (res * x) % mod;
        x = (x * x) % mod;
        n >>= 1;
    }
    return res;
}

// 逆元。オイラーの定理から？
// 有限体上での割り算に利用
// 3/4 = 3*(1/4) = 3x(4の逆数) = 3x3 mod 11
// 4の逆数はかけると1になるので、この場合は3
ll mod_inverse(ll x) {
    return mod_pow(x, mod-2);
}

const int fact_max_n = 1000000;
ll fact[fact_max_n];
ll fact_inv[fact_max_n];

void calc_fact() {
    fact[0] = 1;
    //階乗の算出。かける度にmodを取る。
    for (ll i = 1; i < fact_max_n; i++)
        fact[i] = (fact[i-1] * i) % mod;
    //階乗の逆元の算出。
    //1*2*3 => 1/(1*2*3)
    //1*2 => 1/(1*2*3)*3
    fact_inv[fact_max_n-1] = mod_inverse(fact[fact_max_n-1]);
    for (ll i = fact_max_n-2; i >= 0; i--)
        fact_inv[i] = (fact_inv[i+1] * (i+1)) % mod;
}

//mod付き組み合わせ
// nCk= n!/(n-k)!k! を、modをかませながら演算
ll mod_comb(ll n, ll k) {
    if (n < 0 || k < 0 || n < k) return 0;
    return (fact[n] * fact_inv[k] % mod) * fact_inv[n-k] % mod;
}
*/

//GCD
int gcd(int a, int b) {
    while(1) {
        if (a<b) swap(a, b);
        if(!b) break;
        a %= b;
    }
    return a;
}

int gcd(const vector<int> &list) {
    int a = list[0];
    for(auto i=1; i<list.size(); i++) {
        a = gcd(a, list[i]);
    }
    return a;
}

typedef vector<vi> vvi;

int N, M;
vi k;
vvi s;
vi p;

void input() {
    cin >> N >> M;
    s = vvi(M);
    k = vi(M);
    rep(i,M) {
        cin >> k[i];
        s[i] = vi(k[i]);
        rep(j,k[i]) {
            cin >> s[i][j];
        }
        cin.ignore();
    }
    p = vi(M);
    rep(i,M) cin >> p[i];
    cin.ignore();
}

int solve() {
    int sum = 0;
    for(ull bit=0; bit < (1<< N); bit++) {
        bool failed = false;
        //どのビットが立っている？
        //全ての電球が光るなら+1
        rep(i, M) {
            int input=0;
            rep(j,k[i]) {
                if(bit & 1<<(s[i][j]-1)) input++;
            }
            if( (input%2 != p[i])) {
                failed = true;
                break;
            }
        }
        if(!failed) {
            sum +=1;
        }
    }
    return sum;
}


int main() {
    input();
    cout << solve() << endl;
}

Measured memory_bytes: 256