// #pragma GCC target("avx2") // #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") #include #define rep(i, n) for (int i = 0; i < (int)n; ++i) #define rrep(i, n) for (int i = (int)n - 1; i >= 0; --i) #define ALL(v) v.begin(), v.end() #define pb push_back #define eb emplace_back #define fi first #define se second using namespace std; using ll = long long; using ld = long double; const array YESNO = {"NO", "YES"}; const array YesNo = {"No", "Yes"}; const array yesno = {"no", "yes"}; void YES(bool b = true) { cout << YESNO[b] << '\n'; } void Yes(bool b = true) { cout << YesNo[b] << '\n'; } void yes(bool b = true) { cout << yesno[b] << '\n'; } template inline bool chmax(T& a, const U& b) { if (a < b){ a = b; return true; } return false; } template inline bool chmin(T& a, const U& b) { if (a > b) { a = b; return true; } return false; } template void UNIQUE(vector& v) { sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end())); } template int lb(const vector v, T x) { return distance(v.begin(), lower_bound(v.begin(), v.end(), x)); } template int ub(const vector v, T x) { return distance(v.begin(), upper_bound(v.begin(), v.end(), x)); } /** * @brief 多次元 vector の作成 * @author えびちゃん */ namespace detail { template auto make_vec(vector& sizes, T const& x) { if constexpr (N == 1) { return vector(sizes[0], x); } else { int size = sizes[N-1]; sizes.pop_back(); return vector(size, make_vec(sizes, x)); } } } template auto make_vec(int const(&sizes)[N], T const& x = T()) { vector s(N); for (int i = 0; i < N; ++i) s[i] = sizes[N-i-1]; return detail::make_vec(s, x); } template ostream& operator<<(ostream& os, const vector& v) { for (auto it = v.begin(); it != v.end(); ++it) { if (it == v.begin()) os << *it; else os << ' ' << *it; } return os; } template ostream& operator<<(ostream& os, const pair& p) { os << p.first << ' ' << p.second; return os; } __attribute__((constructor)) void fast_io() { ios::sync_with_stdio(false); cin.tie(nullptr); } #include using namespace atcoder; using mint = modint1000000007; // using mint = modint998244353; int main() { int n, m; cin >> n >> m; auto g = make_vec>({n+1, 0}); auto rg = make_vec>({n+1, 0}); rep(i, m) { ll u, v, l, a; cin >> u >> v >> l >> a; g[u].eb(v, l, a); rg[v].eb(u, l, a); } vector ok(n+1), rok(n+1); auto dfs = [&](auto self, int u) -> void { ok[u] = true; for (auto [v, l, a] : g[u]) { if (ok[v]) continue; self(self, v); } }; auto rdfs = [&](auto self, int u) -> void { rok[u] = true; for (auto [v, l, a] : rg[u]) { if (rok[v]) continue; self(self, v); } }; dfs(dfs, 0); rdfs(rdfs, n); if (!(ok[n] && rok[n])) { cout << 0 << '\n'; return 0; } auto ng = make_vec>({n+1, 0}); vector in(n+1); rep(i, n+1) { if (ok[i] && rok[i]) { for (auto [v, l, a] : g[i]) { if (ok[v] && rok[v]) { ng[i].eb(v, l, a); in[v]++; } } } } queue q; vector topolo; rep(i, n+1) if (in[i] == 0) q.push(i), topolo.pb(i); while (!q.empty()) { int u = q.front(); q.pop(); for (auto [v, l, a] : g[u]) { in[v]--; if (in[v] == 0) { q.push(v); topolo.pb(v); } } } rep(i, n+1) if (in[i] != 0) { cout << "INF\n"; return 0; } vector> dp(n+1); dp[0].fi = 1; for (auto u : topolo) { for (auto [v, l, a] : g[u]) { dp[v].fi += dp[u].fi * a; dp[v].se += (dp[u].se + dp[u].fi * l) * a; } } cout << dp[n].se.val() << '\n'; }