#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include <sstream>
#include <cstring>
#include <numeric>
#include <ctime>
#include <cassert>
#include <random>
//#include <valarray>
//#include <fstream>

#define re return
#define fi first
#define se second
#define mp make_pair
#define pb emplace_back
#define all(x) x.begin(), x.end()
#define sz(x) ((int)(x).size())
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; i--)
#define y0 y32479
#define y1 y95874
#define next next239
#define prev prev239
#define fill(x, y) memset(x, y, sizeof(x))
#define sqr(x) ((x)*(x))
#define sqrt(x) sqrt(abs(x))
#define unq(x) (x.resize(unique(all(x)) - x.begin()))
#define ba back()
#define popcount __builtin_popcountll
#define fastIO() {ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);}

#ifdef LOCAL_BOBER
bool local = true;
#define deb(x) cout << #x << " = " << (x) << endl
#define debn(x, n) { cout << #x << "(" << n << ") = " << \
	"{"; int _f_ = 1; rep(_i_, n) {if (!_f_) cout << "|"; cout << x[_i_]; _f_= 0;} cout << "}" << endl;}
#define deba(x) { cout << #x << " (size: " << sz(x) << ") = " << \
	"{"; int _f_ = 1; for (auto o : x) {if (!_f_) cout << "|"; cout << o; _f_ = 0;} cout << "}" << endl;}
#else
bool local = false;
#define deb(x) ;
#define debn(x, n) ;
#define deba(x) ;
#define endl "\n"
#endif

using namespace std;

typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<string> vs;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef vector<ll> vll;
typedef pair<double, double> pdd;
typedef long double LD;
typedef double D;

template<class T> void print(T v) { cout << sz(v) << endl; for (auto x : v) cout << x << ' '; cout << endl; };
template<class T> void print1(T v) { cout << sz(v) << endl; for (auto x : v) cout << x + 1 << ' '; cout << endl; };
template<class T1, class T2> ostream& operator << (ostream &o, pair<T1, T2> x) {re o << x.fi << ' ' << x.se;}
template<class T1, class T2> istream& operator >> (istream &o, pair<T1, T2> &x) {re o >> x.fi >> x.se;}
template<class T> ostream& operator << (ostream &o, vector<T> &x) {for (auto &el : x) o << el << ' '; re o;}
template<class T> istream& operator >> (istream &o, vector<T> &x) {for (auto &el : x) o >> el; re o;}
template<class T1, class T2> pair<T1, T2> operator + (pair<T1, T2> a, pair<T1, T2> b) {a.fi += b.fi; a.se += b.se; re a;}
template<class T1, class T2> pair<T1, T2> operator - (pair<T1, T2> a, pair<T1, T2> b) {a.fi -= b.fi; a.se -= b.se; re a;}
template<class T1, class T2> void operator += (pair<T1, T2> &a, pair<T1, T2> b) {a.fi += b.fi; a.se += b.se;}
template<class T1, class T2> void operator -= (pair<T1, T2> &a, pair<T1, T2> b) {a.fi -= b.fi; a.se -= b.se;}

int nint() {int x; cin >> x; re x;}
double getTime() { re clock() / (double) CLOCKS_PER_SEC;};

mt19937 rnd(0);
int rand(int n) { re rnd() % n; }
int rand(int l, int r) { re rnd() % (r - l + 1) + l; }

//const int mod = 1000000000 + 7;
const int mod = 998244353;

void initIO() {
	if (local) {
		freopen("input.txt", "r", stdin);
		//freopen("output.txt", "w", stdout);
		srand((int)time(0));
		rnd.seed((int)time(0));
	}
	else {
		//freopen("input.txt", "r", stdin);
		//freopen("output.txt", "w", stdout);
		fastIO();
	}
}

void solve();
void precalc();

int TID;

signed main() {
	initIO();

	int tc = 1;
	cin >> tc;

	precalc();
	rep(tt, tc) {
		TID = tt;
//		cout << "Case #" << tt + 1 << ": ";
		solve();
	}

	if (local)
		cout << endl << "time = " << getTime() << endl;
}

void precalc() {

}

/* ================ actual code starts here ================ */

int n;
int m;

int c[505][505];
int a[1050][505];
int used[1050];
int eq[1050][1050];

set<int> q;

int getRow(int j, int x) {
	rep(i, 2 * n) {
		if (used[i])
			continue;
		if (a[i][j] == x)
			re i;
	}
	assert(0);
	re -1;
}

void del(int i) {
//	deb(i + 0);
	used[i] = -1;
	rep(j, n) {
		c[j][a[i][j]]--;
		if (c[j][a[i][j]] == 1) {
			int r = getRow(j, a[i][j]);
			q.insert(r);
//			cout << "? " << i << ' ' << j << ' ' << a[i][j] << ' ' << r << endl;
		}
	}
}

void add(int i) {
//	deb(i);
	rep(j, n)
		c[j][a[i][j]] = mod;
	del(i);
	rep(j, 2 * n)
	if (!used[j] && eq[i][j])
		del(j);
	used[i] = 1;
}

vi v[1050];

void go(int x, int c) {
	if (c == 0)
		used[x] = 1;
	else
		used[x] = -1;
	for (int y : v[x])
		if (!used[y])
			go(y, c^1);
}

void solve() {
	cin >> n;
	rep(i, n) rep(j, n)
		c[i][j] = 0;

	rep(i, 2 * n) rep(j, n) {
		cin >> a[i][j];
		a[i][j]--;
		c[j][a[i][j]]++;
	}

	rep(i, 2 * n) rep(j, i) {
		int s = 0;
		rep(k, n)
			s += a[i][k] == a[j][k];
		eq[i][j] = eq[j][i] = s;
	}

	fill(used, 0);

	rep(x, n) rep(j, n)
		if (c[j][x] == 1)
			q.insert(getRow(j, x));

	deba(q);

	while (!q.empty()) {
		int i = *q.begin();
		q.erase(i);
		used[i] = 1;
		add(i);
	}

	rep(i, 2 * n)
		v[i].clear();

	rep(i, 2 * n) rep(j, 2 * n)
		if (!used[i] && !used[j] && eq[i][j]) {
			v[i].pb(j);
			v[j].pb(i);
		}

	int e = 1;
	rep(i, 2 * n) {
		if (used[i])
			continue;
		go(i, 0);
		e = e * 2 % mod;
	}

	cout << e << endl;
	rep(i, 2 * n)
	if (used[i] == 1)
		cout << i + 1 << ' ';
	cout << endl;
}










