description: Ivan is playing yet another roguelike computer game. He controls a single hero in the game. The hero has n equipment slots. There is a list of c_i items for the i-th slot, the j-th of them increases the hero strength by a_{i,j}. The items for each slot are pairwise distinct and are listed in the increasing order of their strength increase. So, a_{i,1} < a_{i,2} < ... < a_{i,c_i}.
  
  For each slot Ivan chooses exactly one item. Let the chosen item for the i-th slot be the b_i-th item in the corresponding list. The sequence of choices [b_1, b_2, ..., b_n] is called a build.
  
  The strength of a build is the sum of the strength increases of the items in it. Some builds are banned from the game. There is a list of m pairwise distinct banned builds. It's guaranteed that there's at least one build that's not banned.
  
  What is the build with the maximum strength that is not banned from the game? If there are multiple builds with maximum strength, print any of them.
  
  Input
  
  The first line contains a single integer n (1 ≤ n ≤ 10) — the number of equipment slots.
  
  The i-th of the next n lines contains the description of the items for the i-th slot. First, one integer c_i (1 ≤ c_i ≤ 2 ⋅ 10^5) — the number of items for the i-th slot. Then c_i integers a_{i,1}, a_{i,2}, ..., a_{i,c_i} (1 ≤ a_{i,1} < a_{i,2} < ... < a_{i,c_i} ≤ 10^8).
  
  The sum of c_i doesn't exceed 2 ⋅ 10^5.
  
  The next line contains a single integer m (0 ≤ m ≤ 10^5) — the number of banned builds.
  
  Each of the next m lines contains a description of a banned build — a sequence of n integers b_1, b_2, ..., b_n (1 ≤ b_i ≤ c_i).
  
  The builds are pairwise distinct, and there's at least one build that's not banned.
  
  Output
  
  Print the build with the maximum strength that is not banned from the game. If there are multiple builds with maximum strength, print any of them.
  
  Examples
  
  Input
  
  
  3
  3 1 2 3
  2 1 5
  3 2 4 6
  2
  3 2 3
  3 2 2
  
  
  Output
  
  
  2 2 3 
  
  
  Input
  
  
  3
  3 1 2 3
  2 1 5
  3 2 4 6
  2
  3 2 3
  2 2 3
  
  
  Output
  
  
  1 2 3
  
  
  Input
  
  
  3
  3 1 2 3
  2 1 5
  3 2 4 6
  2
  3 2 3
  2 2 3
  
  
  Output
  
  
  3 2 2
  
  
  Input
  
  
  4
  1 10
  1 4
  1 7
  1 3
  0
  
  
  Output
  
  
  1 1 1 1 
solution: import java.io.*;
  import java.util.*;
  
  public class D {
  
  	static int[][] mat;
  
  	static int compare(int[] x, int[] y) {
  		for (int i = 0; i < x.length; i++) {
  			if (x[i] != y[i])
  				return x[i] - y[i];
  		}
  		return 0;
  	}
  
  	static class node {
  		int sum;
  		int[] arr;
  
  		public node(int s, int[] a) {
  			sum = s;
  			arr = a;
  		}
  
  	}
  
  	public static void main(String[] args) throws IOException {
  		Scanner sc = new Scanner(System.in);
  		PrintWriter pw = new PrintWriter(System.out);
  
  		int t = 1;
  		while (t-- > 0) {
  			int n = sc.nextInt();
  
  			mat = new int[n][];
  			for (int i = 0; i < mat.length; i++) {
  				int size = sc.nextInt();
  				mat[i] = new int[size];
  				for (int j = 0; j < mat[i].length; j++) {
  					mat[i][j] = sc.nextInt();
  				}
  			}
  
  			int m = sc.nextInt();
  			TreeSet<int[]> hs = new TreeSet<>((u, v) -> compare(v, u));
  			for (int i = 0; i < m; i++) {
  				int[] temp = new int[n];
  				for (int j = 0; j < n; j++) {
  					temp[j] = sc.nextInt();
  				}
  				hs.add(temp);
  			}
  
  			TreeSet<int[]> pq = new TreeSet<>((u, v) -> compare(v, u));
  			int[] temp = new int[n + 1];
  			for (int i = 0; i < n; i++) {
  				temp[i + 1] = mat[i].length;
  				temp[0] += mat[i][mat[i].length - 1];
  			}
  			pq.add(temp);
  			int[] ans = new int[n];
  			while (true) {
  				ans = pq.pollFirst();
  //				System.out.println("now");
  //				System.out.println(Arrays.toString(ans));
  				int[] ser = new int[n];
  				for (int i = 0; i < ser.length; i++) {
  					ser[i] = ans[i + 1];
  				}
  				if (!hs.contains(ser)) {
  					break;
  				}
  				for (int i = 0; i < n; i++) {
  					if (ans[i+1] == 1)
  						continue;
  
  					int[] b = ans.clone();
  					b[0] -= mat[i][b[i+1] - 1];
  					b[i+1]--;
  					b[0] += mat[i][b[i+1] - 1];
  //					System.out.println(Arrays.toString(b));
  					pq.add(b);
  				}
  			}
  
  			for (int i = 1; i < ans.length; i++) {
  				pw.print(ans[i]+" ");
  			} 
  
  //			pw.println(" I have the sol but .... no time to write it !!  :(");
  		}
  
  		pw.flush();
  	}
  
  	public class SegmentTree { // 1-based DS, OOP
  
  		int N; // the number of elements in the array as a power of 2 (i.e. after padding)
  		int[] array, sTree, lazy;
  
  		SegmentTree(int[] in) {
  			array = in;
  			N = in.length - 1;
  			sTree = new int[N << 1]; // no. of nodes = 2*N - 1, we add one to cross out index zero
  			lazy = new int[N << 1];
  			build(1, 1, N);
  		}
  
  		void build(int node, int b, int e) // O(n)
  		{
  			if (b == e)
  				sTree[node] = array[b];
  			else {
  				int mid = b + e >> 1;
  				build(node << 1, b, mid);
  				build(node << 1 | 1, mid + 1, e);
  				sTree[node] = sTree[node << 1] + sTree[node << 1 | 1];
  			}
  		}
  
  		void update_point(int index, int val) // O(log n)
  		{
  			index += N - 1;
  			sTree[index] += val;
  			while (index > 1) {
  				index >>= 1;
  				sTree[index] = sTree[index << 1] + sTree[index << 1 | 1];
  			}
  		}
  
  		void update_range(int i, int j, int val) // O(log n)
  		{
  			update_range(1, 1, N, i, j, val);
  		}
  
  		void update_range(int node, int b, int e, int i, int j, int val) {
  			if (i > e || j < b)
  				return;
  			if (b >= i && e <= j) {
  				sTree[node] += (e - b + 1) * val;
  				lazy[node] += val;
  			} else {
  				int mid = b + e >> 1;
  				propagate(node, b, mid, e);
  				update_range(node << 1, b, mid, i, j, val);
  				update_range(node << 1 | 1, mid + 1, e, i, j, val);
  				sTree[node] = sTree[node << 1] + sTree[node << 1 | 1];
  			}
  
  		}
  
  		void propagate(int node, int b, int mid, int e) {
  			lazy[node << 1] += lazy[node];
  			lazy[node << 1 | 1] += lazy[node];
  			sTree[node << 1] += (mid - b + 1) * lazy[node];
  			sTree[node << 1 | 1] += (e - mid) * lazy[node];
  			lazy[node] = 0;
  		}
  
  		int query(int i, int j) {
  			return query(1, 1, N, i, j);
  		}
  
  		int query(int node, int b, int e, int i, int j) // O(log n)
  		{
  			if (i > e || j < b)
  				return 0;
  			if (b >= i && e <= j)
  				return sTree[node];
  			int mid = b + e >> 1;
  			propagate(node, b, mid, e);
  			int q1 = query(node << 1, b, mid, i, j);
  			int q2 = query(node << 1 | 1, mid + 1, e, i, j);
  			return q1 + q2;
  
  		}
  
  	}
  
  	static ArrayList<Integer> primes;
  	static int[] isComposite;
  
  	static void sieve(int N) // O(N log log N)
  	{
  		isComposite = new int[N + 1];
  		isComposite[0] = isComposite[1] = 1; // 0 indicates a prime number
  		primes = new ArrayList<Integer>();
  
  		for (int i = 2; i <= N; ++i) // can loop till i*i <= N if primes array is not needed O(N log log sqrt(N))
  			if (isComposite[i] == 0) // can loop in 2 and odd integers for slightly better performance
  			{
  				primes.add(i);
  				if (1l * i * i <= N)
  					for (int j = i * i; j <= N; j += i) // j = i * 2 will not affect performance too much, may alter in
  														// modified sieve
  						isComposite[j] = 1;
  			}
  	}
  
  	static char[] bits;
  
  	static class Trie {
  		static final int R = 2;
  
  		static class Node {
  			Node[] next = new Node[R];
  			int count = 0;
  		}
  
  		Node root = new Node();
  
  		void insert(String s) {
  			Node cur = root;
  			cur.count++;
  			for (int i = 0; i < s.length(); i++) {
  				int idx = s.charAt(i) == '0' ? 0 : 1;
  				Node nxt = cur.next[idx];
  				if (nxt == null)
  					nxt = cur.next[idx] = new Node();
  				cur = nxt;
  				cur.count++;
  			}
  		}
  
  		void insert(int n) {
  			Node cur = root;
  			cur.count++;
  			for (int i = 29; i >= 0; i--) {
  				int idx = (n >> i) & 1;
  				Node nxt = cur.next[idx];
  				if (nxt == null)
  					nxt = cur.next[idx] = new Node();
  				cur = nxt;
  				cur.count++;
  			}
  		}
  
  		void remove(String s) {
  			Node cur = root;
  			cur.count--;
  			for (int i = 0; i < s.length(); i++) {
  				int idx = s.charAt(i) == '0' ? 0 : 1;
  				Node nxt = cur.next[idx];
  				cur = nxt;
  				cur.count--;
  			}
  		}
  
  		int query(String x) {
  			Node cur = root;
  			String ans = "";
  			for (int i = 0; i < x.length(); i++) {
  				int idx = x.charAt(i) == '0' ? 1 : 0;
  				Node nxt = cur.next[idx];
  				if (nxt == null || nxt.count == 0) {
  					ans += 0;
  					nxt = cur.next[idx ^ 1];
  				} else
  					ans += 1;
  				cur = nxt;
  			}
  			return Integer.parseInt(ans, 2);
  		}
  
  		int query2(String x) {
  			Node cur = root;
  			String ans = "";
  			for (int i = 0; i < x.length(); i++) {
  				int idx = x.charAt(i) == '0' ? 1 : 0;
  				Node nxt = cur.next[idx];
  				if (nxt == null || nxt.count == 0) {
  					ans += 0;
  					nxt = cur.next[idx ^ 1];
  				} else
  					ans += 1;
  				cur = nxt;
  			}
  			return Integer.parseInt(ans, 2);
  		}
  	}
  
  	static class Scanner {
  		StringTokenizer st;
  		BufferedReader br;
  
  		public Scanner(InputStream s) {
  			br = new BufferedReader(new InputStreamReader(s));
  		}
  
  		public String next() throws IOException {
  			while (st == null || !st.hasMoreTokens())
  				st = new StringTokenizer(br.readLine());
  			return st.nextToken();
  		}
  
  		public int nextInt() throws IOException {
  			return Integer.parseInt(next());
  		}
  
  		public long nextLong() throws IOException {
  			return Long.parseLong(next());
  		}
  
  		public String nextLine() throws IOException {
  			return br.readLine();
  		}
  
  		public double nextDouble() throws IOException {
  			String x = next();
  			StringBuilder sb = new StringBuilder("0");
  			double res = 0, f = 1;
  			boolean dec = false, neg = false;
  			int start = 0;
  			if (x.charAt(0) == '-') {
  				neg = true;
  				start++;
  			}
  			for (int i = start; i < x.length(); i++)
  				if (x.charAt(i) == '.') {
  					res = Long.parseLong(sb.toString());
  					sb = new StringBuilder("0");
  					dec = true;
  				} else {
  					sb.append(x.charAt(i));
  					if (dec)
  						f *= 10;
  				}
  			res += Long.parseLong(sb.toString()) / f;
  			return res * (neg ? -1 : 1);
  		}
  
  		public boolean ready() throws IOException {
  			return br.ready();
  		}
  
  	}
  }