← Home
package main

import (
	"io"
	"os"
	"sort"
	"strconv"
)

const MOD int64 = 1000000007

type FastScanner struct {
	data []byte
	idx  int
	n    int
}

func NewFastScanner() *FastScanner {
	data, _ := io.ReadAll(os.Stdin)
	return &FastScanner{data: data, n: len(data)}
}

func (fs *FastScanner) NextInt() int {
	for fs.idx < fs.n && (fs.data[fs.idx] < '0' || fs.data[fs.idx] > '9') {
		fs.idx++
	}
	val := 0
	for fs.idx < fs.n && fs.data[fs.idx] >= '0' && fs.data[fs.idx] <= '9' {
		val = val*10 + int(fs.data[fs.idx]-'0')
		fs.idx++
	}
	return val
}

type Entry struct {
	t int
	g int
	c int
}

type Entries []Entry

func (e Entries) Len() int { return len(e) }
func (e Entries) Less(i, j int) bool {
	if e[i].t != e[j].t {
		return e[i].t < e[j].t
	}
	return e[i].g < e[j].g
}
func (e Entries) Swap(i, j int) { e[i], e[j] = e[j], e[i] }

func main() {
	fs := NewFastScanner()
	n := fs.NextInt()
	m := fs.NextInt()

	entries := make([]Entry, 0, 500000)

	for gym := 1; gym <= n; gym++ {
		gi := fs.NextInt()
		arr := make([]int, gi)
		for i := 0; i < gi; i++ {
			arr[i] = fs.NextInt()
		}
		sort.Ints(arr)
		cnt := 1
		for i := 1; i <= gi; i++ {
			if i < gi && arr[i] == arr[i-1] {
				cnt++
			} else {
				entries = append(entries, Entry{t: arr[i-1], g: gym, c: cnt})
				cnt = 1
			}
		}
	}

	sort.Sort(Entries(entries))

	children := make(map[uint64]int, len(entries)*2+1)
	nodeCount := make([]int, 1, len(entries)+1)

	usedTypes := 0
	for i := 0; i < len(entries); {
		t := entries[i].t
		node := 0
		for i < len(entries) && entries[i].t == t {
			key := (uint64(node) << 40) | (uint64(entries[i].g) << 20) | uint64(entries[i].c)
			next, ok := children[key]
			if !ok {
				next = len(nodeCount)
				children[key] = next
				nodeCount = append(nodeCount, 0)
			}
			node = next
			i++
		}
		nodeCount[node]++
		usedTypes++
	}

	nodeCount[0] = m - usedTypes

	ans := int64(1)
	for _, c := range nodeCount {
		for i := 2; i <= c; i++ {
			ans = (ans * int64(i)) % MOD
		}
	}

	os.Stdout.WriteString(strconv.FormatInt(ans, 10))
}