Problem:
Score : 400 points

Problem Statement

There is a directed graph with N vertices and M edges.
The i-th edge (1≤i≤M) points from vertex a_i to vertex b_i, and has a weight c_i.
We will play the following single-player game using this graph and a piece.

Initially, the piece is placed at vertex 1, and the score of the player is set to 0.
The player can move the piece as follows:

When the piece is placed at vertex a_i, move the piece along the i-th edge to vertex b_i. After this move, the score of the player is increased by c_i.

The player can end the game only when the piece is placed at vertex N.
The given graph guarantees that it is possible to traverse from vertex 1 to vertex N.

When the player acts optimally to maximize the score at the end of the game, what will the score be?
If it is possible to increase the score indefinitely, print inf.

Constraints

2≤N≤1000

1≤M≤min(N(N-1),2000)

1≤a_i,b_i≤N (1≤i≤M)

a_i≠b_i (1≤i≤M)

a_i≠a_j or b_i≠b_j (1≤i<j≤M)

-10^9≤c_i≤10^9 (1≤i≤M)

c_i is an integer.

In the given graph, there exists a path from vertex 1 to vertex N.

Input

Input is given from Standard Input in the following format:

N M
a_1 b_1 c_1
a_2 b_2 c_2
:
a_M b_M c_M

Output

Print the maximum possible score at the end of the game, if it is finite. If it is possible to increase the score indefinitely, print inf.

Sample Input 1

3 3
1 2 4
2 3 3
1 3 5

Sample Output 1

7

There are two ways to move the piece to vertex N=3:

vertex 1 → vertex 2 → vertex 3 : score 4+3=7

vertex 1 → vertex 3 : score 5

Thus, the maximum possible score at the end of the game is 7.

Sample Input 2

2 2
1 2 1
2 1 1

Sample Output 2

inf

It is possible to increase the score indefinitely by alternating between vertex 1 and 2.

Sample Input 3

6 5
1 2 -1000000000
2 3 -1000000000
3 4 -1000000000
4 5 -1000000000
5 6 -1000000000

Sample Output 3

-5000000000

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

#region using
using System;
using System.Collections.Generic;
using System.Linq;
using IEnumerable = System.Collections.IEnumerable;
using IEnumerator = System.Collections.IEnumerator;
using BitArray = System.Collections.BitArray;
using BigInteger = System.Numerics.BigInteger;
using TextReader = System.IO.TextReader;
using System.Text;
#endregion

namespace AtCoderProject
{
    public class Program
    {
        public object Calc()
        {
            var N = consoleReader.Int;
            var M = consoleReader.Int;
            {
                var gb = new GraphBuilder(N);
                foreach (var cr in consoleReader.Repeat(M))
                    gb.Add(cr.Int - 1, cr.Int - 1, cr.Int);
                graph = gb.ToArray();
                var fromStart = CanStart(0);
                gb = new GraphBuilder(N);
                for (int i = 0; i < N; i++)
                    if (fromStart.Contains(i))
                        foreach (var c in graph[i].children)
                            if (fromStart.Contains(c.to))
                                gb.Add(i, c.to, c.length);
                graph = gb.ToArray();
                var canGoal = CanGo(N - 1);
                gb = new GraphBuilder(N);
                for (int i = 0; i < N; i++)
                    if (canGoal.Contains(i))
                        foreach (var c in graph[i].children)
                            if (canGoal.Contains(c.to))
                                gb.Add(i, c.to, c.length);
                graph = gb.ToArray();
            }
            scores = Enumerable.Repeat((long)-1e13, N).ToArray();
            scores[0] = 0;
            sumi = new HashSet<int>();
            loopStatus = new bool[graph.Length];
            try
            {
                CalcScore(0);
                return scores[N - 1];
            }
            catch
            {
                return "inf";
            }
        }

        long[] scores;
        HashSet<int> sumi;
        void CalcScore(int v)
        {
            if (!sumi.Add(v)) return;
            loopStatus[v] = true;
            foreach (var c in graph[v].children)
            {
                long nextScore = scores[v] + c.length;
                if (scores[c.to] < nextScore)
                    if (loopStatus[c.to])
                        throw new Exception();
                    else
                        scores[c.to] = nextScore;
            }
            foreach (var c in graph[v].children)
            {
                CalcScore(c.to);
            }
            loopStatus[v] = false;
        }

        Node[] graph;

        bool[] loopStatus;
        HashSet<int> CanGo(int to) => CanGo(to, new HashSet<int>());
        HashSet<int> CanGo(int to, HashSet<int> result)
        {
            if (result.Add(to))
                foreach (var c in graph[to].roots)
                    CanGo(c.to, result);
            return result;
        }
        HashSet<int> CanStart(int from) => CanStart(from, new HashSet<int>());
        HashSet<int> CanStart(int from, HashSet<int> result)
        {
            if (result.Add(from))
                foreach (var c in graph[from].children)
                    CanStart(c.to, result);
            return result;
        }

        class GraphBuilder
        {
            private List<Next>[] roots;
            private List<Next>[] children;
            public GraphBuilder(int count)
            {
                this.roots = new List<Next>[count];
                this.children = new List<Next>[count];
                for (int i = 0; i < count; i++)
                {
                    this.roots[i] = new List<Next>();
                    this.children[i] = new List<Next>();
                }
            }
            public GraphBuilder(int count, IEnumerable<int[]> arrays) : this(count)
            {
                foreach (var item in arrays)
                    this.Add(item[0], item[1], item[2]);
            }
            public void Add(int from, int to, int length)
            {
                children[from].Add(new Next { to = to, length = length });
                roots[to].Add(new Next { to = from, length = length });
            }
            public Node[] ToArray() =>
                Enumerable
                .Zip(roots, children, (r, c) => Tuple.Create(r, c))
                .Select((t, i) => new Node(i, t.Item1.ToArray(), t.Item2.ToArray()))
                .ToArray();
        }
        public struct Next
        {
            public int to;
            public int length;
        }
        public class Node : IEquatable<Node>
        {
            public Node(int i, Next[] roots, Next[] children)
            {
                this.index = i;
                this.roots = roots;
                this.children = children;
            }
            public int index;
            public Next[] roots;
            public Next[] children;

            public override bool Equals(object obj)
            {
                if (obj is Node)
                    return this.Equals((Node)obj);
                else
                    return false;
            }
            public bool Equals(Node other) => this.index == other.index;
            public override int GetHashCode() => this.index;
        }

        #region いつもの
#pragma warning disable
        private ConsoleReader consoleReader;
        public Program(ConsoleReader consoleReader) { this.consoleReader = consoleReader; }
        static void Main() => Console.WriteLine(new Program(new ConsoleReader(Console.In)).Calc()); static string AllLines<T>(IEnumerable<T> source) => string.Join("\n", source);
    }
    static class Ext
    {
        public static Dictionary<TKey, int> GroupCount<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) => source.GroupBy(keySelector).ToDictionary(g => g.Key, g => g.Count());
        public static Dictionary<TKey, int> GroupCount<TKey>(this IEnumerable<TKey> source) => source.GroupCount(i => i);
    }
    public class ConsoleReader { private string[] ReadLineSplit() => textReader.ReadLine().Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries); private string[] line = Array.Empty<string>(); private int linePosition; private TextReader textReader; public ConsoleReader(TextReader tr) { textReader = tr; } public int Int => int.Parse(String); public long Long => long.Parse(String); public double Double => double.Parse(String); public string String { get { if (linePosition >= line.Length) { linePosition = 0; line = ReadLineSplit(); } return line[linePosition++]; } } public class SplitLine { private string[] splited; public SplitLine(ConsoleReader cr) { splited = cr.ReadLineSplit(); cr.line = Array.Empty<string>(); } public int[] Int => String.Select(x => int.Parse(x)).ToArray(); public int[] Int0 => String.Select(x => int.Parse(x) - 1).ToArray(); public long[] Long => String.Select(x => long.Parse(x)).ToArray(); public double[] Double => String.Select(x => double.Parse(x)).ToArray(); public string[] String => splited; } public SplitLine Split => new SplitLine(this); public class RepeatReader : IEnumerable<ConsoleReader> { ConsoleReader cr; int count; public RepeatReader(ConsoleReader cr, int count) { this.cr = cr; this.count = count; } public IEnumerator<ConsoleReader> GetEnumerator() => Enumerable.Repeat(cr, count).GetEnumerator(); System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerable<string> String => this.Select(cr => cr.String); public IEnumerable<int> Int => this.Select(cr => cr.Int); public IEnumerable<int> Int0 => this.Select(cr => cr.Int - 1); public IEnumerable<long> Long => this.Select(cr => cr.Long); public IEnumerable<double> Double => this.Select(cr => cr.Double); } public RepeatReader Repeat(int count) => new RepeatReader(this, count); }
    #endregion
}