← Home
package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"time"
)

type Box struct {
	items []int
	pos   map[int]int
}

type Move struct {
	src, dst, item int
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	getInt := func() int {
		var res int
		var started bool
		for {
			b, err := reader.ReadByte()
			if err != nil {
				break
			}
			if b >= '0' && b <= '9' {
				res = res*10 + int(b-'0')
				started = true
			} else if started {
				break
			}
		}
		return res
	}

	n := getInt()
	m_presents := getInt()
	_ = m_presents

	if n == 0 {
		return
	}

	boxes := make([]Box, n+1)
	s := make([]int, n+1)
	S := 0

	for i := 1; i <= n; i++ {
		s[i] = getInt()
		S += s[i]
		boxes[i].items = make([]int, 0, s[i])
		boxes[i].pos = make(map[int]int, s[i])
		for j := 0; j < s[i]; j++ {
			val := getInt()
			boxes[i].items = append(boxes[i].items, val)
			boxes[i].pos[val] = j
		}
	}

	if S == 0 {
		fmt.Println(0)
		return
	}

	L := S / n
	R := (S + n - 1) / n
	if S%n == 0 {
		R = L
	}

	d_prime := make([]int, n+1)
	sum_prime := 0
	for i := 1; i <= n; i++ {
		if s[i] > R {
			d_prime[i] = R
		} else if s[i] < L {
			d_prime[i] = L
		} else {
			d_prime[i] = s[i]
		}
		sum_prime += d_prime[i]
	}

	if sum_prime < S {
		for i := 1; i <= n && sum_prime < S; i++ {
			if d_prime[i] == L {
				d_prime[i] = R
				sum_prime++
			}
		}
	} else if sum_prime > S {
		for i := 1; i <= n && sum_prime > S; i++ {
			if d_prime[i] == R {
				d_prime[i] = L
				sum_prime--
			}
		}
	}

	var sources []int
	var sinks []int
	for i := 1; i <= n; i++ {
		diff := s[i] - d_prime[i]
		for j := 0; j < diff; j++ {
			sources = append(sources, i)
		}
		for j := 0; j < -diff; j++ {
			sinks = append(sinks, i)
		}
	}

	moves := make([]Move, 0, len(sources))
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))

	for k := 0; k < len(sources); k++ {
		src := sources[k]
		dst := sinks[k]

		var item int
		for {
			idx := rng.Intn(len(boxes[src].items))
			item = boxes[src].items[idx]
			if _, has := boxes[dst].pos[item]; !has {
				break
			}
		}

		moves = append(moves, Move{src, dst, item})

		idx := boxes[src].pos[item]
		last := boxes[src].items[len(boxes[src].items)-1]
		boxes[src].items[idx] = last
		boxes[src].pos[last] = idx
		boxes[src].items = boxes[src].items[:len(boxes[src].items)-1]
		delete(boxes[src].pos, item)

		boxes[dst].items = append(boxes[dst].items, item)
		boxes[dst].pos[item] = len(boxes[dst].items) - 1
	}

	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	fmt.Fprintln(out, len(moves))
	for _, move := range moves {
		fmt.Fprintln(out, move.src, move.dst, move.item)
	}
}