#include<iostream>
#include<stdlib.h>
#include<vector>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<map>
#include<math.h>
#include<iomanip>
#include<set>

#define rep(i,n) for(ll i = 0; i < (ll)n; i++)
#define swap(a,b) a^=b;b^=a;a^=b;
//#define for(i,a,b) for (ll i=(a);i<(ll)b; i++)
#define print(x) std::cout << x << std::endl;

using namespace std;

typedef long long ll;

template<class T, class U> std::string replace(std::string s, const T& target, const U& replacement, bool replace_first = 0, bool replace_empty = 0);
bool isContain(int value, int under, int top);
vector<int> range(int x);

int get_ab(string str) {
	bool isA = false;
	int res = 0;
	if (str[0] == 'A') isA = true;
	for (int i = 1; i < str.length(); i++) {
		if (isA && str[i] == 'B') { res++; isA = false; }
		else if (str[i] == 'A') isA = true;
		else isA = false;
	}
	return res;
}

vector<bool> isVisited;
vector<int> Accu;
vector<vector<int>> Datas;
int N;

void DEF(int pos,int sum) {
	bool all_visited = true;
	rep(i,N) 
		if (isVisited[i] == false) {
			all_visited = false;
			break;
		}

	Accu[pos] = sum;

	rep(i, N) {
		if (isVisited[i] == true) continue; //すでに訪れている
		if (Datas[pos][i] == -1)  continue; //繋がっていない
		isVisited[i] = true;
		DEF(i, sum + Datas[pos][i]);
	}
}

ll gcd(ll A, ll B) {
	int r = A % B;
	while (r != 0) {
		A = B;
		B = r;
		r = A % B;
	}

	return B;
}

vector<bool> to_binary(int x) {
	vector<bool> res;
	while (x != 0) {
		res.push_back(x % 2);
		x /= 2;
	}
	return res;
}

vector<bool> pad(vector<bool> inp,int num) {
	while (inp.size() != num) {
		inp.push_back(false);
	}
	return inp;
}

vector<bool> proc(int x,int n) {
	vector<bool> res = pad(to_binary(x), n);
	reverse(res.begin(), res.end());
	return res;
}

int main(void) {
	//Program Start	

	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];
		}
	}

	rep(i, M) {
		cin >> p[i];
	}

	int loopcount = (int)pow(2, N);
	int ans = 0;

	rep(i, loopcount) {
		vector<bool> onof = proc(i, N);


		//すべての電球
		int is_all_lig = true;
		rep(j, M) {
			//すべてのスイッチ
			int switch_count = 0;
			//cout << "Hello" << endl;
			rep (l, K[j]) {
				switch_count += onof[s[j][l] - 1] ? 1 : 0;
			}
			if (switch_count % 2 != p[j]) { //光っていなかったら
				is_all_lig = false;
				break;
			}
		}
		if (is_all_lig)
			ans++;
	}

	cout << ans << endl;




ProgramEndPointLabel:;


	//Program End
	system("pause");

	return 0;
}


vector<int> range(int y) {
	vector<int> result(y);
	for (int i = 0; i < y; i++)
		result[i] = i;
	return result;
}

bool isContain(int value, int under, int top) {
	if (under <= value && value <= top) return true;
	return false;
}

template<class T, class U> std::string replace(std::string s, const T& target, const U& replacement, bool replace_first, bool replace_empty) {
	using S = std::string;
	using C = std::string::value_type;
	using N = std::string::size_type;
	struct {
		auto len(const S& s) { return s.size(); }
		auto len(const C* p) { return std::char_traits<C>::length(p); }
		auto len(const C  c) { return 1; }
		auto sub(S* s, const S& t, N pos, N len) { s->replace(pos, len, t); }
		auto sub(S* s, const C* t, N pos, N len) { s->replace(pos, len, t); }
		auto sub(S* s, const C  t, N pos, N len) { s->replace(pos, len, 1, t); }
		auto ins(S* s, const S& t, N pos) { s->insert(pos, t); }
		auto ins(S* s, const C* t, N pos) { s->insert(pos, t); }
		auto ins(S* s, const C  t, N pos) { s->insert(pos, 1, t); }
	} util;

	N target_length = util.len(target);
	N replacement_length = util.len(replacement);
	if (target_length == 0) {
		if (!replace_empty || replacement_length == 0) return s;
		N n = s.size() + replacement_length * (1 + s.size());
		s.reserve(!replace_first ? n : s.size() + replacement_length);
		for (N i = 0; i < n; i += 1 + replacement_length) {
			util.ins(&s, replacement, i);
			if (replace_first) break;
		}
		return s;
	}

	N pos = 0;
	while ((pos = s.find(target, pos)) != std::string::npos) {
		util.sub(&s, replacement, pos, target_length);
		if (replace_first) return s;
		pos += replacement_length;
	}
	return s;
}


Measured memory_bytes: 504