#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < n; ++i)
#define REPR(i, n) for (int i = n - 1; i >= 0; --i)
#define FOR(i, a, b) for (int i = a; i < b; ++i)
#define FORR(i, a, b) for (int i = b - 1; i >= a; --i)
#define SORT(v) sort(v.begin(), v.end())
#define SORTR(v) sort(v.rbegin(), v.rend())
#define REV(v) reverse(v.begin(), v.end())
#define ITER(itr, v) for (auto itr = v.begin(); itr != v.end(); ++itr)
#define LB(v, x) (lower_bound(v.begin(), v.end(), x) - v.begin())
#define UB(v, x) (upper_bound(v.begin(), v.end(), x) - v.begin())
#define SZ(v) (int)v.size()
using namespace std;
using ll = long long;
using P = pair<int, int>;

class Zp {
	const int p = 998244353;
	ll r;
	void set(ll x) {
		while (x < 0) x += p;
		r = x % p;
	}

public:
	Zp(ll x) { set(x); }
	Zp() { set(0); }

	Zp operator-() const { return Zp(-r); }
	Zp &operator=(ll y) {
		set(y);
		return *this;
	}
	Zp &operator=(const Zp &y) { return *this = y.r; }

	Zp &operator+=(ll y) {
		set(r + y);
		return *this;
	}
	Zp &operator-=(ll y) { return *this += -y; }
	Zp &operator*=(ll y) {
		set(r * y);
		return *this;
	}
	Zp &operator/=(ll y) { return *this *= inv(y); }
	Zp operator+(ll y) const { return Zp(r + y); }
	Zp operator-(ll y) const { return *this + (-y); }
	Zp operator*(ll y) const { return Zp(r * y); }
	Zp operator/(ll y) const { return *this * inv(y); }

	Zp &operator+=(const Zp &y) { return *this += y.r; }
	Zp &operator-=(const Zp &y) { return *this -= y.r; }
	Zp &operator*=(const Zp &y) { return *this *= y.r; }
	Zp &operator/=(const Zp &y) { return *this /= y.r; }
	Zp operator+(const Zp &y) const { return *this + y.r; }
	Zp operator-(const Zp &y) const { return *this - y.r; }
	Zp operator*(const Zp &y) const { return *this * y.r; }
	Zp operator/(const Zp &y) const { return *this / y.r; }

	Zp pow(int n) const {
		if (n == 0) return 1;
		if (n % 2) return *this * pow(n - 1);
		Zp tmp = pow(n / 2);
		return tmp * tmp;
	}
	Zp inv(int x) const { return Zp(x).pow(p - 2); }
	Zp inv() const { return inv(r); }

	ll get() const { return r; }

	friend istream &operator>>(istream &istr, Zp &x) {
		istr >> x.r;
		x.set(x.r);
		return istr;
	}
	friend ostream &operator<<(ostream &ostr, const Zp &x) {
		ostr << x.r;
		return ostr;
	}
};
class Comb {
	vector<Zp> fact, ifact;

public:
	Comb(int N) : fact(N + 1), ifact(N + 1) {
		fact[0] = 1;
		REP(i, N)
		fact[i + 1] = fact[i] * (i + 1);
		ifact[N] = fact[N].inv();
		REPR(i, N)
		ifact[i] = ifact[i + 1] * (i + 1);
	}
	Zp operator()(int n, int k) const {
		return fact[n] * ifact[n - k] * ifact[k];
	}
	Zp f(int k) const { return fact[k]; }
	Zp invf(int k) const { return ifact[k]; }
};

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);

	int N, M;
	cin >> N >> M;
	vector<int> k(M);
	vector<vector<int>> s(M);
	vector<int> p(M);
	REP(i, M) {
		cin >> k[i];
		s[i].resize(k[i]);
		REP(j, k[i]) {
			cin >> s[i][j];
			s[i][j]--;
		}
	}
	REP(i, M) { cin >> p[i]; }
	int res = 0;
	for (int bit = 0; bit < (1 << N); ++bit) {
		int cnt = 0;
		REP(i, M) {
			int sum = 0;
			REP(j, k[i]) {
				sum += (bit >> s[i][j] & 1);
			}
			if (sum % 2 == p[i]) ++cnt;
		}
		if (cnt == M) ++res;
	}
	cout << res << endl;

	return 0;
}

Measured memory_bytes: 256