/**
* @file qoj7612-1.cpp
* @author n685
* @brief
* @date 2024-01-29
*
*
*/
#ifndef LOCAL
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#endif
#include <bits/stdc++.h>
#ifdef LOCAL
#include "dd/debug.h"
#else
#define dbg(...) 42
#define dbgR(...) 4242
#define dbgP(...) 420
#define dbgRP(...) 420420
void nline() {}
#endif
template <class T> std::pair<T, T> exEucl(T a, T b) {
if (a < b) {
// auto [x, y] = exEucl(b, a);
T x, y;
std::tie(x, y) = exEucl(b, a);
return {y, x};
}
if (b == 0) {
assert(a == 1);
return {1, 0};
}
// auto [x, y] = exEucl(b, a % b);
T x, y;
std::tie(x, y) = exEucl(b, a % b);
return {y, x - (a / b) * y};
}
template <
class T, class U,
typename std::enable_if<std::is_integral<U>::value, bool>::type = true>
T binpow(T a, U b) {
// 0^0 = 1
T res = 1;
while (b > 0) {
if (b % 2 == 1) {
res *= a;
}
a *= a;
b /= 2;
}
return res;
}
template <class Md, class V = int64_t> struct Mod {
using T = typename std::decay<decltype(Md::value)>::type;
T val = 0;
template <class U> static T normalize(U val) {
if (val <= -Md::value || Md::value <= val) {
val %= Md::value;
}
if (val < 0) {
val += Md::value;
}
return static_cast<T>(val);
}
Mod() : val(0) {}
template <class U, typename std::enable_if<std::is_integral<U>::value,
bool>::type = true>
Mod(U _val) {
val = normalize(_val);
}
// addition
Mod &operator+=(Mod b) {
val += b.val;
if (val >= Md::value) {
val -= Md::value;
}
return *this;
}
friend Mod operator+(Mod a, Mod b) { return (a += b); }
Mod &operator++() { return (*this += 1); }
Mod operator++(int) {
Mod res = *this;
++(*this);
return res;
}
// subtraction
Mod &operator-=(Mod b) {
val -= b.val;
if (val < 0) {
val += Md::value;
}
return *this;
}
friend Mod operator-(Mod a, Mod b) { return (a -= b); }
Mod &operator--() { return (*this -= 1); }
Mod operator--(int) {
Mod res = *this;
--(*this);
return res;
}
// multiplication
Mod &operator*=(Mod b) {
val = static_cast<T>(static_cast<V>(val) * b.val % Md::value);
return *this;
}
friend Mod operator*(Mod a, Mod b) { return (a *= b); }
template <class U> Mod binpow(U b) const { return ::binpow(*this, b); }
Mod inv() const {
return Mod(exEucl(static_cast<V>(val), static_cast<V>(Md::value)).first);
// return binpow(Md::value - 2);
}
// comparison
bool operator==(Mod b) const { return (val == b.val); }
// auto operator<=>(const Mod &b) const = default;
bool operator!=(Mod b) const { return (val != b.val); }
bool operator<(Mod b) const { return (val < b.val); }
bool operator>(Mod b) const { return (val > b.val); }
bool operator<=(Mod b) const { return (val <= b.val); }
bool operator>=(Mod b) const { return (val >= b.val); }
// io
friend std::istream &operator>>(std::istream &in, Mod &a) {
V v;
in >> v;
a = Mod(v);
return in;
}
friend std::ostream &operator<<(std::ostream &out, const Mod &a) {
out << a.val;
return out;
}
// conversion
explicit operator T() const { return val; }
const T &operator()() const { return val; }
Mod operator-() const { return Mod(-val); }
};
const int MOD = (int)1e9 + 7;
using Mint = Mod<std::integral_constant<std::decay<decltype(MOD)>::type, MOD>>;
using Row = std::vector<Mint>;
Row operator+=(Row &a, Row b) {
if (a.size() < b.size()) {
a.resize(b.size());
}
for (int i = 0; i < (int)a.size(); ++i) {
a[i] += b[i];
}
return a;
}
Row operator+(Row a, Row b) { return (a += b); }
Row operator-=(Row &a, Row b) {
if (a.size() < b.size()) {
a.resize(b.size());
}
for (int i = 0; i < (int)a.size(); ++i) {
a[i] -= b[i];
}
return a;
}
Row operator-(Row a, Row b) { return (a -= b); }
Row operator*=(Row &a, Mint b) {
for (int i = 0; i < (int)a.size(); ++i) {
a[i] *= b;
}
return a;
}
Row operator*(Row a, Mint b) { return a *= b; }
Row operator*(Mint b, Row a) { return a *= b; }
using Mat = std::vector<Row>;
Row operator*(Mat a, Row b) {
int n = (int)a.size();
Row c(n);
for (int i = 0; i < n; ++i) {
for (int k = 0; k < n; ++k) {
c[i] += a[i][k] * b[k];
}
}
return c;
}
template <class T> auto operator*(std::vector<std::vector<T>> a, Mat b) {
int n = (int)a.size(), m = (int)b[0].size();
// Mat c(n, Row(m));
std::vector c(n, std::vector<T>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
for (int k = 0; k < (int)a[0].size(); ++k) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
return c;
}
std::vector<Mint> gauss(std::vector<Row> eq) {
if ((int)eq.size() == 0) {
return {};
}
int n = (int)eq.size();
int m = (int)eq[0].size() - 1;
assert(n >= m);
for (int i = 0; i < m; ++i) {
int ind = i;
while (ind < n && eq[ind][i] == 0) {
++ind;
}
if (ind == n) {
std::exit(-1);
}
std::swap(eq[i], eq[ind]);
eq[i] *= eq[i][i].inv();
for (int j = 0; j < n; ++j) {
if (j != i) {
eq[j] -= eq[j][i] * eq[i];
}
}
}
std::vector<Mint> sol(m);
for (int i = 0; i < m; ++i) {
sol[i] = eq[i].back();
}
return sol;
}
int main() {
#ifdef LOCAL
std::freopen("input.txt", "r", stdin);
std::freopen("output.txt", "w", stdout);
#else
std::cin.tie(nullptr)->sync_with_stdio(false);
#endif
int n;
std::cin >> n;
std::vector a(n, std::vector<Mint>(n)), c(n, std::vector<Mint>(n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
std::cin >> a[i][j];
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
std::cin >> c[i][j];
}
}
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
// std::vector<int> r(n);
// std::iota(r.begin(), r.end(), 0);
// std::shuffle(r.begin(), r.end(), rng);
// r.resize(std::min(n, 20));
std::vector<int> row, col;
{
Row rr(n);
for (int i = 0; i < n; ++i) {
rr[i] = (int)(rng() % MOD);
}
Row rr2 = c * (a * rr);
for (int i = 0; i < n; ++i) {
if (rr[i] != rr2[i]) {
row.push_back(i);
}
}
}
{
Mat rr(1, Row(n));
for (int i = 0; i < n; ++i) {
rr[0][i] = (int)(rng() % MOD);
}
Mat rr2 = (rr * a) * c;
for (int i = 0; i < n; ++i) {
if (rr[0][i] != rr2[0][i]) {
col.push_back(i);
}
}
}
const int m = (int)row.size() * (int)col.size();
assert((int)row.size() <= 12 && (int)col.size() <= 12);
// std::vector val(n, std::vector(n, Row(m + 1)));
// for (int i = 0; i < n; ++i) {
// for (int j = 0; j < n; ++j) {
// val[i][j].back() = c[i][j];
// }
// }
// for (int i = 0; i < (int)row.size(); ++i) {
// for (int j = 0; j < (int)col.size(); ++j) {
// val[row[i]][col[j]].back() = 0;
// val[row[i]][col[j]][(int)col.size() * i + j] = 1;
// }
// }
std::vector<Mint> sol(m);
for (int i = 0; i < (int)row.size(); ++i) {
std::vector<Row> eq;
std::vector val(n, Row((int)col.size() + 1));
for (int j = 0; j < n; ++j) {
val[j].back() = c[row[i]][j];
}
for (int j = 0; j < (int)col.size(); ++j) {
val[col[j]][j] = 1;
val[col[j]].back() = 0;
}
// std::vector res = (std::vector({val}) * a)[0];
// for (int j : col) {
for (int j = 0; j < n; ++j) {
Row r((int)col.size() + 1);
for (int k = 0; k < n; ++k) {
r += val[k] * a[k][j];
}
r.back() = (int)(row[i] == j) - r.back();
for (int k = 0; k < (int)col.size(); ++k) {
if (r[k] != 0) {
eq.push_back(r);
break;
}
}
}
std::vector lsol = gauss(eq);
assert(lsol.size() == col.size());
for (int j = 0; j < (int)col.size(); ++j) {
sol[(int)col.size() * i + j] = lsol[j];
}
}
std::vector<std::pair<std::pair<int, int>, Mint>> ans;
for (int i = 0; i < (int)row.size(); ++i) {
for (int j = 0; j < (int)col.size(); ++j) {
Mint v = sol[(int)col.size() * i + j];
if (c[row[i]][col[j]] != v) {
ans.emplace_back(std::pair{row[i], col[j]}, v);
}
}
}
std::cout << (int)ans.size() << '\n';
for (auto [aa, b] : ans) {
std::cout << aa.first + 1 << ' ' << aa.second + 1 << ' ' << b << '\n';
}
}