var input = require("fs").readFileSync("/dev/stdin", "utf8").trim().split("\n");
var obj = {
  "list" : input,
  "index" : 0,
  "max" : input.length,
  "next" : function(){
    if(!this.hasNext()){throw "NoSuchElementException:次に要素は無いよ";}
    var returnObj = this.list[this.index];
    this.index++;
    return returnObj;
  },
  "hasNext" : function(){return (this.index < this.max);}
}
Main();
function next(){return obj.next();}
function hasNext(){return obj.hasNext();}
function myout(t){console.log(t);}//standard output
function myerr(t){console.error(t);}//standard error
//[no]要素の扱い。数値型
//不明値、異常時:引数そのまま返す　1:数値へ変換
//2:半角SPで分割 4:半角SPで分割し、数値配列へ
//6:1文字で分割  7:1文字で分割し、数値配列へ
//8:半角SPで結合 9:改行で結合 0:文字なしで結合
function myconv(i,no){try{switch(no){case 1:return parseInt(i);case 2:return i.split(" ");case 4:return i.split(" ").map((a)=>Number(a));case 6:return i.split("");case 7:return i.split("").map((a)=>Number(a));case 8:return i.join(" ");case 9:return i.join("\n");case 0:return i.join("");default:return i;}}catch(e){return i;}}
function Main(){
  var one = myconv(next(),4);
  var N = one[0];
  var M = one[1];
  var list = [];
  for(var i = 0; i < M; i++){
    var tmp = myconv(next(),4);
    tmp.shift();
    list.push(tmp);
  }
  var p = myconv(next(),4);
  var output = 0;
  //スイッチの状態0~2^N-1
  for(var i = 0; i < (1 << N); i++){
    //電球がついてる個数(これ==Mになったらパターン+1)
    var allon = 0;
    
    //ある電球がついてるかどうか。
    for(var j = 0; j < M; j++){
      
      //電球とつながってるスイッチがONの個数
      var on = 0;
      for(var k = 0; k < list[j].length; k++){
        if((i & (1 << (N - list[j][k]))) != 0){
          //myerr(i.toString(2) + " & (1 << " + (list[j][k] - 1) + ") = " + (i & (1 << (list[j][k] - 1))));
           on++;
        }
      }
      if(on % 2 == p[j]){
        //myerr(j + "個目の電球がついた" + i.toString(2) + " " + on);
         allon++;
      }
    }
    if(allon == M){
      //myerr(i.toString(2) + " 全部の電球がついた");
      output++;
    }
  }
  myout(output);
}