#include #include #include #include #include #include using namespace std; mt19937 mt(530629); // Berlekamp–Massey algorithm // https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm // Complexity: O(N^2) // input: S = sequence from field K // return: L = degree of minimal polynomial, // C_reversed = monic min. polynomial (size = L + 1, reversed order, C_reversed[0] = 1)) // Formula: convolve(S, C_reversed)[i] = 0 for i >= L // Example: // - [1, 2, 4, 8, 16] -> (1, [1, -2]) // - [1, 1, 2, 3, 5, 8] -> (2, [1, -1, -1]) // - [0, 0, 0, 0, 1] -> (5, [1, 0, 0, 0, 0, 998244352]) (mod 998244353) // - [] -> (0, [1]) // - [0, 0, 0] -> (0, [1]) // - [-2] -> (1, [1, 2]) template std::pair> find_linear_recurrence(const std::vector &S) { int N = S.size(); using poly = std::vector; poly C_reversed{1}, B{1}; int L = 0, m = 1; Tfield b = 1; // adjust: C(x) <- C(x) - (d / b) x^m B(x) auto adjust = [](poly C, const poly &B, Tfield d, Tfield b, int m) -> poly { C.resize(std::max(C.size(), B.size() + m)); Tfield a = d / b; for (unsigned i = 0; i < B.size(); i++) C[i + m] -= a * B[i]; return C; }; for (int n = 0; n < N; n++) { Tfield d = S[n]; for (int i = 1; i <= L; i++) d += C_reversed[i] * S[n - i]; if (d == 0) m++; else if (2 * L <= n) { poly T = C_reversed; C_reversed = adjust(C_reversed, B, d, b, m); L = n + 1 - L; B = T; b = d; m = 1; } else C_reversed = adjust(C_reversed, B, d, b, m++); } return std::make_pair(L, C_reversed); } template std::vector gen_random_vector(int len) { static std::uniform_int_distribution rnd(1, ModInt::mod() - 1); std::vector ret(len); for (auto &x : ret) x = rnd(mt); return ret; }; // Sparse matrix template struct sparse_matrix { int H, W; std::vector>> vals; sparse_matrix(int H = 0, int W = 0) : H(H), W(W), vals(H) {} int height() const { return H; } int width() const { return W; } void add_element(int i, int j, Tp val) { assert(i >= 0 and i < H); assert(j >= 0 and i < W); vals[i].emplace_back(j, val); } std::vector prod(const std::vector &vec) const { assert(W == int(vec.size())); std::vector ret(H); for (int i = 0; i < H; i++) { for (const auto &p : vals[i]) ret[i] += p.second * vec[p.first]; } return ret; } }; template int blackbox_rank(const Matrix &M) { assert(M.height() == M.width()); const int N = M.height(); std::vector b = gen_random_vector(N), u = gen_random_vector(N), D = gen_random_vector(N); std::vector uMDib(2 * N); for (int i = 0; i < 2 * N; i++) { uMDib[i] = std::inner_product(u.begin(), u.end(), b.begin(), Tp(0)); for (int j = 0; j < N; j++) b[j] *= D[j]; b = M.prod(b); } return find_linear_recurrence(uMDib).first - 1; } #include using mint = atcoder::modint1000000007; uniform_int_distribution rndgen(0, mint::mod()); int solve(int r, const vector> &uvws) { const int m = uvws.size(); // Geelen & Iwata (2005) sparse_matrix mat(r + m * 2, r + m * 2); for (int i = 0; i < m; ++i) { auto [u, v, w] = uvws[i]; mat.add_element(u, r + i * 2, +1); mat.add_element(w, r + i * 2, -1); mat.add_element(v, r + i * 2 + 1, +1); mat.add_element(w, r + i * 2 + 1, -1); mat.add_element(r + i * 2, u, +1); mat.add_element(r + i * 2, w, -1); mat.add_element(r + i * 2 + 1, v, +1); mat.add_element(r + i * 2 + 1, w, -1); } for (int i = 0; i < m; ++i) { int x = rndgen(mt); mat.add_element(r + i * 2, r + i * 2 + 1, x); mat.add_element(r + i * 2 + 1, r + i * 2, -x); } int rank = blackbox_rank, mint>(mat); return rank / 2 - m; } int main() { int N, M; cin >> N >> M; vector> uvws; while (M--) { int u, v, w; cin >> u >> v >> w; u--, v--, w--; uvws.emplace_back(u, v, w); } cout << max(solve(N, uvws), solve(N, uvws)) << '\n'; }