#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 60*2;
const int max_in = 12;
int level[maxn];
int from[maxn], to[maxn], flow[maxn], cap[maxn];
int head[maxn], nex[maxn], cnt[maxn];
int P, N;
int s, t;
int e = 0;
void add_edge(int u, int v, int weight1){
from[e] = u, to[e] = v, cap[e] = weight1, nex[e] = head[u], head[u] = e;
e++;
from[e] = v, to[e] = u, cap[e] = 0, nex[e] = head[v], head[v] = e;
e++;
return;
}
int bfs(int s){
queue<int> q;
while(!q.empty()) q.pop();
memset(level, -1, sizeof(level));
level[s] = 0;
q.push(s);
while(!q.empty()){
int temp = q.front();
q.pop();
for(int e=head[temp]; e!=-1; e=nex[e]){
if(cap[e]>flow[e]&&level[to[e]]<0){
level[to[e]] = level[temp] + 1;
q.push(to[e]);
}
}
}
}
int dfs(int u ,int t, int f){
if(u == t) return f;
for(int& e = cnt[u]; e!=-1; e=nex[e]){
if(cap[e]>flow[e] && level[from[e]]<level[to[e]]){
int d = dfs(to[e], t, min(f, cap[e]-flow[e]));
if(d>0){
flow[e] += d;
flow[e^1] -= d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t){
int flow = 0;
for(;;){
bfs(s);
if(level[t]<0) return flow;
int f;
memcpy(cnt, head, sizeof(head));
while(true){
if((f = dfs(s, t, INF))<=0){
break;
}
flow += f;
}
}
return flow;
}
struct Node{
int in[max_in], out[max_in];
int in_number, out_number;
Node(){
this->in_number = 0;
this->out_number = 0;
}
}node[maxn>>1];
int main()
{
while(~scanf("%d%d", &P, &N)){
e = 0;
s = 0, t = 2*N+1;
memset(head, -1, sizeof(head));
for(int i=1; i<=N; i++){
int wei;
scanf("%d", &wei);
add_edge(i, i+N, wei);
for(int j=0; j<P; j++){
scanf("%d", &node[i].in[j]);
if(node[i].in[j] == 1)node[i].in_number++;
}
for(int j=0; j<P; j++){
scanf("%d", &node[i].out[j]);
if(node[i].out[j] == 0) node[i].out_number++;
}
if(node[i].in_number == 0) add_edge(s, i, INF);
if(node[i].out_number == 0) add_edge(i+N, t, INF);
for(int j=1; j<i; j++){
if(node[j].out_number!=0&&node[i].in_number!=0){
bool flag = true;
for(int k=0; k<P&&flag; k++){
if(node[j].out[k]+node[i].in[k] == 1){
flag = false;
}
}
if(flag){
add_edge(j+N, i, INF);
}
}
}
for(int j=1; j<i; j++){
if(node[j].in_number!=0&&node[i].out_number!=0){
bool flag = true;
for(int k=0; k<P&&flag; k++){
if(node[j].in[k]+node[i].out[k] == 1){
flag = false;
}
}
if(flag){
add_edge(i+N, j, INF);
}
}
}
}
printf("%d ", max_flow(s, t));
int tot=0;
for(int i=0; i<e; i++){
if(flow[i]<=0||from[i] == s || to[i] == t || to[i] - from[i]==N){
continue;
}
from[tot] = from[i]-N>0?from[i]-N:from[i];
to[tot] = to[i]-N>0?to[i]-N:to[i];
flow[tot] = flow[i];
tot++;
}
printf("%d\n", tot);
for(int i=0; i<tot; i++){
printf("%d %d %d\n", from[i], to[i], flow[i]);
}
}
return 0;
}