The map of Bertown can be represented as a set of $$$n$$$ intersections, numbered from $$$1$$$ to $$$n$$$ and connected by $$$m$$$ one-way roads. It is possible to move along the roads from any intersection to any other intersection. The length of some path from one intersection to another is the number of roads that one has to traverse along the path. The shortest path from one intersection $$$v$$$ to another intersection $$$u$$$ is the path that starts in $$$v$$$, ends in $$$u$$$ and has the minimum length among all such paths.Polycarp lives near the intersection $$$s$$$ and works in a building near the intersection $$$t$$$. Every day he gets from $$$s$$$ to $$$t$$$ by car. Today he has chosen the following path to his workplace: $$$p_1$$$, $$$p_2$$$, ..., $$$p_k$$$, where $$$p_1 = s$$$, $$$p_k = t$$$, and all other elements of this sequence are the intermediate intersections, listed in the order Polycarp arrived at them. Polycarp never arrived at the same intersection twice, so all elements of this sequence are pairwise distinct. Note that you know Polycarp's path beforehand (it is fixed), and it is not necessarily one of the shortest paths from $$$s$$$ to $$$t$$$.Polycarp's car has a complex navigation system installed in it. Let's describe how it works. When Polycarp starts his journey at the intersection $$$s$$$, the system chooses some shortest path from $$$s$$$ to $$$t$$$ and shows it to Polycarp. Let's denote the next intersection in the chosen path as $$$v$$$. If Polycarp chooses to drive along the road from $$$s$$$ to $$$v$$$, then the navigator shows him the same shortest path (obviously, starting from $$$v$$$ as soon as he arrives at this intersection). However, if Polycarp chooses to drive to another intersection $$$w$$$ instead, the navigator rebuilds the path: as soon as Polycarp arrives at $$$w$$$, the navigation system chooses some shortest path from $$$w$$$ to $$$t$$$ and shows it to Polycarp. The same process continues until Polycarp arrives at $$$t$$$: if Polycarp moves along the road recommended by the system, it maintains the shortest path it has already built; but if Polycarp chooses some other path, the system rebuilds the path by the same rules.Here is an example. Suppose the map of Bertown looks as follows, and Polycarp drives along the path $$$[1, 2, 3, 4]$$$ ($$$s = 1$$$, $$$t = 4$$$): Check the picture by the link http://tk.codeforces.com/a.png   When Polycarp starts at $$$1$$$, the system chooses some shortest path from $$$1$$$ to $$$4$$$. There is only one such path, it is $$$[1, 5, 4]$$$;  Polycarp chooses to drive to $$$2$$$, which is not along the path chosen by the system. When Polycarp arrives at $$$2$$$, the navigator rebuilds the path by choosing some shortest path from $$$2$$$ to $$$4$$$, for example, $$$[2, 6, 4]$$$ (note that it could choose $$$[2, 3, 4]$$$);  Polycarp chooses to drive to $$$3$$$, which is not along the path chosen by the system. When Polycarp arrives at $$$3$$$, the navigator rebuilds the path by choosing the only shortest path from $$$3$$$ to $$$4$$$, which is $$$[3, 4]$$$;  Polycarp arrives at $$$4$$$ along the road chosen by the navigator, so the system does not have to rebuild anything. Overall, we get $$$2$$$ rebuilds in this scenario. Note that if the system chose $$$[2, 3, 4]$$$ instead of $$$[2, 6, 4]$$$ during the second step, there would be only $$$1$$$ rebuild (since Polycarp goes along the path, so the system maintains the path $$$[3, 4]$$$ during the third step).The example shows us that the number of rebuilds can differ even if the map of Bertown and the path chosen by Polycarp stays the same. Given this information (the map and Polycarp's path), can you determine the minimum and the maximum number of rebuilds that could have happened during the journey?

The first line contains two integers $$$n$$$ and $$$m$$$ ($$$2 \le n \le m \le 2 \cdot 10^5$$$) — the number of intersections and one-way roads in Bertown, respectively. Then $$$m$$$ lines follow, each describing a road. Each line contains two integers $$$u$$$ and $$$v$$$ ($$$1 \le u, v \le n$$$, $$$u \ne v$$$) denoting a road from intersection $$$u$$$ to intersection $$$v$$$. All roads in Bertown are pairwise distinct, which means that each ordered pair $$$(u, v)$$$ appears at most once in these $$$m$$$ lines (but if there is a road $$$(u, v)$$$, the road $$$(v, u)$$$ can also appear). The following line contains one integer $$$k$$$ ($$$2 \le k \le n$$$) — the number of intersections in Polycarp's path from home to his workplace. The last line contains $$$k$$$ integers $$$p_1$$$, $$$p_2$$$, ..., $$$p_k$$$ ($$$1 \le p_i \le n$$$, all these integers are pairwise distinct) — the intersections along Polycarp's path in the order he arrived at them. $$$p_1$$$ is the intersection where Polycarp lives ($$$s = p_1$$$), and $$$p_k$$$ is the intersection where Polycarp's workplace is situated ($$$t = p_k$$$). It is guaranteed that for every $$$i \in [1, k - 1]$$$ the road from $$$p_i$$$ to $$$p_{i + 1}$$$ exists, so the path goes along the roads of Bertown.

Print two integers: the minimum and the maximum number of rebuilds that could have happened during the journey.

/*
URL:
https://codeforces.com/problemset/problem/1320/B
*/

package main

import (
	"bufio"
	"container/heap"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := ReadString()
//i := ReadInt()
//X := ReadIntSlice(n)
//S := ReadRuneSlice()
//a := ReadFloat64()
//A := ReadFloat64Slice(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*******************************************************************/

const (
	// General purpose
	MOD          = 1000000000 + 7
	ALPHABET_NUM = 26
	INF_INT64    = math.MaxInt64
	INF_BIT60    = 1 << 60
	INF_INT32    = math.MaxInt32
	INF_BIT30    = 1 << 30
	NIL          = -1

	// for dijkstra, prim, and so on
	WHITE = 0
	GRAY  = 1
	BLACK = 2
)

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	ReadString = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

var (
	n, m int
	k    int
	P    []int

	G  [200000 + 50][]Edge
	RG [200000 + 50][]Edge

	cnts [200000 + 50]int
)

func main() {
	n, m = ReadInt2()
	for i := 0; i < m; i++ {
		u, v := ReadInt2()
		u--
		v--

		// 逆向きに貼る
		G[v] = append(G[v], Edge{to: u, cost: 1})
		RG[u] = append(RG[u], Edge{to: v, cost: 1})
	}
	k = ReadInt()
	P = ReadIntSlice(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	dp, _ := dijkstra(P[k-1], n, G[:n])
	PrintfDebug("dp: %v\n", dp)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]

		if dp[cid]-1 < dp[nid] {
			mini++
			maxi++
			continue
		}

		ok := false
		for _, e := range RG[cid] {
			if dp[cid] == dp[e.to]+1 && e.to != nid {
				ok = true
				break
			}
		}
		if ok {
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

type (
	Edge struct {
		to   int
		cost int
	}
	Vertex struct {
		pri int
		id  int
	}
)

const INF_DIJK = 1 << 30

func dijkstra(sid, n int, AG [][]Edge) (dp, parents []int) {
	dp = make([]int, n)
	parents = make([]int, n)
	colors := make([]int, n)
	for i := 0; i < n; i++ {
		dp[i] = INF_DIJK
		colors[i], parents[i] = WHITE, -1
	}

	temp := make(VertexPQ, 0, 100000+5)
	pq := &temp
	heap.Init(pq)
	heap.Push(pq, &Vertex{pri: 0, id: sid})
	dp[sid] = 0
	colors[sid] = GRAY

	for pq.Len() > 0 {
		pop := heap.Pop(pq).(*Vertex)

		colors[pop.id] = BLACK

		if pop.pri > dp[pop.id] {
			continue
		}

		for _, e := range AG[pop.id] {
			if colors[e.to] == BLACK {
				continue
			}

			if dp[e.to] > dp[pop.id]+e.cost {
				dp[e.to] = dp[pop.id] + e.cost
				heap.Push(pq, &Vertex{pri: dp[e.to], id: e.to})
				colors[e.to], parents[e.to] = GRAY, pop.id
			}
		}
	}

	return dp, parents
}

type VertexPQ []*Vertex

func (pq VertexPQ) Len() int           { return len(pq) }
func (pq VertexPQ) Less(i, j int) bool { return pq[i].pri < pq[j].pri } // <: ASC, >: DESC
func (pq VertexPQ) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}
func (pq *VertexPQ) Push(x interface{}) {
	item := x.(*Vertex)
	*pq = append(*pq, item)
}
func (pq *VertexPQ) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

// how to use
// temp := make(VertexPQ, 0, 100000+1)
// pq := &temp
// heap.Init(pq)
// heap.Push(pq, &Vertex{pri: intValue})
// popped := heap.Pop(pq).(*Vertex)

/*******************************************************************/

/*********** I/O ***********/

var (
	// ReadString returns a WORD string.
	ReadString func() string
	stdout     *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// ReadInt returns an integer.
func ReadInt() int {
	return int(readInt64())
}
func ReadInt2() (int, int) {
	return int(readInt64()), int(readInt64())
}
func ReadInt3() (int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64())
}
func ReadInt4() (int, int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64()), int(readInt64())
}

// ReadInt64 returns as integer as int64.
func ReadInt64() int64 {
	return readInt64()
}
func ReadInt64_2() (int64, int64) {
	return readInt64(), readInt64()
}
func ReadInt64_3() (int64, int64, int64) {
	return readInt64(), readInt64(), readInt64()
}
func ReadInt64_4() (int64, int64, int64, int64) {
	return readInt64(), readInt64(), readInt64(), readInt64()
}

func readInt64() int64 {
	i, err := strconv.ParseInt(ReadString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// ReadIntSlice returns an integer slice that has n integers.
func ReadIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt()
	}
	return b
}

// ReadInt64Slice returns as int64 slice that has n integers.
func ReadInt64Slice(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt64()
	}
	return b
}

// ReadFloat64 returns an float64.
func ReadFloat64() float64 {
	return float64(readFloat64())
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(ReadString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func ReadFloat64Slice(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadFloat64()
	}
	return b
}

// ReadRuneSlice returns a rune slice.
func ReadRuneSlice() []rune {
	return []rune(ReadString())
}

/*********** Debugging ***********/

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

// Strtoi is a wrapper of strconv.Atoi().
// If strconv.Atoi() returns an error, Strtoi calls panic.
func Strtoi(s string) int {
	if i, err := strconv.Atoi(s); err != nil {
		panic(errors.New("[argument error]: Strtoi only accepts integer string"))
	} else {
		return i
	}
}

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintfDebug is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func PrintfDebug(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// PrintfBufStdout is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func PrintfBufStdout(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*
URL:
https://codeforces.com/problemset/problem/1320/B
*/

package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := ReadString()
//i := ReadInt()
//X := ReadIntSlice(n)
//S := ReadRuneSlice()
//a := ReadFloat64()
//A := ReadFloat64Slice(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*******************************************************************/

const (
	// General purpose
	MOD          = 1000000000 + 7
	ALPHABET_NUM = 26
	INF_INT64    = math.MaxInt64
	INF_BIT60    = 1 << 60
	INF_INT32    = math.MaxInt32
	INF_BIT30    = 1 << 30
	NIL          = -1

	// for dijkstra, prim, and so on
	WHITE = 0
	GRAY  = 1
	BLACK = 2
)

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	ReadString = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

var (
	n, m int
	k    int
	P    []int

	// G  [200000 + 50][]Edge
	// RG [200000 + 50][]Edge
	G  [200000 + 50][]int
	RG [200000 + 50][]int

	cnts [200000 + 50]int
)

func main() {
	n, m = ReadInt2()
	for i := 0; i < m; i++ {
		u, v := ReadInt2()
		u--
		v--

		// 逆向きに貼る
		// G[v] = append(G[v], Edge{to: u, cost: 1})
		// RG[u] = append(RG[u], Edge{to: v, cost: 1})

		G[v] = append(G[v], u)
		RG[u] = append(RG[u], v)
	}
	k = ReadInt()
	P = ReadIntSlice(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	// dp, _ := dijkstra(P[k-1], n, G[:n])
	dp, _ := SSSPByBFS(P[k-1], n, G[:n])
	PrintfDebug("dp: %v\n", dp)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]

		if dp[cid]-1 < dp[nid] {
			mini++
			maxi++
			continue
		}

		ok := false
		for _, e := range RG[cid] {
			// if dp[cid] == dp[e.to]+1 && e.to != nid {
			// 	ok = true
			// 	break
			// }
			if dp[cid] == dp[e]+1 && e != nid {
				ok = true
				break
			}
		}
		if ok {
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

func SSSPByBFS(sid, n int, AG [][]int) (dp []int, visited []bool) {
	dp = make([]int, n)
	visited = make([]bool, n)

	for i := 0; i < n; i++ {
		dp[i] = INF_BIT30
		visited[i] = false
	}

	Q := []Node{}
	dp[sid] = 0
	visited[sid] = true
	Q = append(Q, Node{id: sid, cost: dp[sid]})

	for len(Q) > 0 {
		cnode := Q[0]
		Q = Q[1:]

		for _, nid := range G[cnode.id] {
			// 訪問済みならパス
			if visited[nid] {
				continue
			}

			dp[nid] = cnode.cost + 1
			visited[nid] = true
			Q = append(Q, Node{id: nid, cost: dp[nid]})
		}
	}

	return dp, visited
}

type Node struct {
	id, cost int
}

/*******************************************************************/

/*********** I/O ***********/

var (
	// ReadString returns a WORD string.
	ReadString func() string
	stdout     *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// ReadInt returns an integer.
func ReadInt() int {
	return int(readInt64())
}
func ReadInt2() (int, int) {
	return int(readInt64()), int(readInt64())
}
func ReadInt3() (int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64())
}
func ReadInt4() (int, int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64()), int(readInt64())
}

// ReadInt64 returns as integer as int64.
func ReadInt64() int64 {
	return readInt64()
}
func ReadInt64_2() (int64, int64) {
	return readInt64(), readInt64()
}
func ReadInt64_3() (int64, int64, int64) {
	return readInt64(), readInt64(), readInt64()
}
func ReadInt64_4() (int64, int64, int64, int64) {
	return readInt64(), readInt64(), readInt64(), readInt64()
}

func readInt64() int64 {
	i, err := strconv.ParseInt(ReadString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// ReadIntSlice returns an integer slice that has n integers.
func ReadIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt()
	}
	return b
}

// ReadInt64Slice returns as int64 slice that has n integers.
func ReadInt64Slice(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt64()
	}
	return b
}

// ReadFloat64 returns an float64.
func ReadFloat64() float64 {
	return float64(readFloat64())
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(ReadString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func ReadFloat64Slice(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadFloat64()
	}
	return b
}

// ReadRuneSlice returns a rune slice.
func ReadRuneSlice() []rune {
	return []rune(ReadString())
}

/*********** Debugging ***********/

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

// Strtoi is a wrapper of strconv.Atoi().
// If strconv.Atoi() returns an error, Strtoi calls panic.
func Strtoi(s string) int {
	if i, err := strconv.Atoi(s); err != nil {
		panic(errors.New("[argument error]: Strtoi only accepts integer string"))
	} else {
		return i
	}
}

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintfDebug is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func PrintfDebug(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// PrintfBufStdout is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func PrintfBufStdout(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*
URL:
https://codeforces.com/contest/1320/problem/B
*/

package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

var (
	n, m int
	k    int
	P    []int

	G  [200000 + 50][]int
	RG [200000 + 50][]int

	cnts [200000 + 50]int
)

func main() {
	defer stdout.Flush()

	n, m = readi2()
	for i := 0; i < m; i++ {
		u, v := readi2()
		u--
		v--

		G[v] = append(G[v], u)
		RG[u] = append(RG[u], v)
	}
	k = readi()
	P = readis(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	dp, _ := SSSPByBFS(P[k-1], n, G[:n], 1)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]

		if dp[cid]-1 < dp[nid] {
			mini++
			maxi++
			continue
		}

		ok := false
		for _, e := range RG[cid] {
			if dp[cid] == dp[e]+1 && e != nid {
				ok = true
				break
			}
		}
		if ok {
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

// verified by https://codeforces.com/contest/1320/problem/B
func SSSPByBFS(sid int, n int, AG [][]int, edgeCost int) (dp []int, visited []bool) {
	const INF_SSSP = 1 << uint(30)

	dp = make([]int, n)
	visited = make([]bool, n)

	for i := 0; i < n; i++ {
		dp[i] = INF_SSSP
		visited[i] = false
	}

	Q := []Node{}
	dp[sid] = 0
	visited[sid] = true
	Q = append(Q, Node{id: sid, cost: dp[sid]})

	for len(Q) > 0 {
		cnode := Q[0]
		Q = Q[1:]

		for _, nid := range AG[cnode.id] {
			if visited[nid] {
				continue
			}

			dp[nid] = cnode.cost + edgeCost
			visited[nid] = true
			Q = append(Q, Node{id: nid, cost: dp[nid]})
		}
	}

	return dp, visited
}

type Node struct {
	id, cost int
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

// abs is integer version of math.Abs
func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

// pow is integer version of math.Pow
// pow calculate a power by Binary Power (二分累乗法(O(log e))).
func pow(a, e int) int {
	if a < 0 || e < 0 {
		panic(errors.New("[argument error]: PowInt does not accept negative integers"))
	}

	if e == 0 {
		return 1
	}

	if e%2 == 0 {
		halfE := e / 2
		half := pow(a, halfE)
		return half * half
	}

	return a * pow(a, e-1)
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	r := bufio.NewReader(os.Stdin)
	var n, m int
	fmt.Fscan(r, &n, &m)

	g := make([][]int, n)
	rg := make([][]int, n)
	for i := 0; i < m; i++ {
		var u, v int
		fmt.Fscan(r, &u, &v)
		u--
		v--
		g[u] = append(g[u], v)
		rg[v] = append(rg[v], u)
	}
	var k int
	fmt.Fscan(r, &k)
	p := make([]int, k)
	for i := 0; i < k; i++ {
		fmt.Fscan(r, &p[i])
		p[i]--
	}
	min, max := solve(g, rg, p)
	fmt.Println(min, max)
}

func solve(g, rg [][]int, p []int) (int, int) {
	k := len(p)
	d := dijkstra(rg, p[k-1])
	var min, max int
	for i := 0; i < k-1; i++ {
		if d[p[i]] != d[p[i+1]]+1 {
			min++
		}
		for _, v := range g[p[i]] {
			if v != p[i+1] && d[p[i]] == d[v]+1 {
				max++
				break
			}
		}
	}
	return min, max
}

func dijkstra(g [][]int, src int) []int {
	n := len(g)
	d := make([]int, n)
	for i := 0; i < n; i++ {
		d[i] = -1
	}
	d[src] = 0
	q := []int{src}
	for len(q) > 0 {
		cur := q[0]
		q = q[1:]
		for _, v := range g[cur] {
			if d[v] == -1 {
				d[v] = d[cur] + 1
				q = append(q, v)
			}
		}
	}
	return d
}

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	r := bufio.NewReader(os.Stdin)
	var n, m int
	fmt.Fscan(r, &n, &m)

	g := make([][]int, n+1)
	rg := make([][]int, n+1)
	for i := 0; i < m; i++ {
		var u, v int
		fmt.Fscan(r, &u, &v)
		g[u] = append(g[u], v)
		rg[v] = append(rg[v], u)
	}
	var k int
	fmt.Fscan(r, &k)
	p := make([]int, k)
	for i := 0; i < k; i++ {
		fmt.Fscan(r, &p[i])
	}
	min, max := solve(g, rg, p)
	fmt.Println(min, max)
}

func solve(g, rg [][]int, p []int) (int, int) {
	k := len(p)
	d := dijkstra(rg, p[k-1])
	var min, max int
	for i := 0; i < k-1; i++ {
		if d[p[i]] != d[p[i+1]]+1 {
			min++
		}
		for _, v := range g[p[i]] {
			if v != p[i+1] && d[p[i]] == d[v]+1 {
				max++
				break
			}
		}
	}
	return min, max
}

func dijkstra(g [][]int, src int) []int {
	n := len(g)
	d := make([]int, n)
	for i := 0; i < n; i++ {
		d[i] = -1
	}
	d[src] = 0
	q := []int{src}
	for len(q) > 0 {
		cur := q[0]
		q = q[1:]
		for _, v := range g[cur] {
			if d[v] == -1 {
				d[v] = d[cur] + 1
				q = append(q, v)
			}
		}
	}
	return d
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"sync"
)

type Edge struct {
	to   int
	next int
}

var edge [200005 * 2] Edge
var head [200005] int
var edge1 [200005 * 2] Edge
var head1 [200005] int
var ans, cnt, cnt1, t, mi, ma int
var q [200005]int
var a [200005] int
var vis [200005] int
var dis [200005] int

func add(u, v int) {
	cnt++
	edge[cnt].to = v
	edge[cnt].next = head[u]
	head[u] = cnt
}
func add1(u, v int) {
	cnt1++
	edge1[cnt1].to = v
	edge1[cnt1].next = head1[u]
	head1[u] = cnt1
}
func bfs(s int, n int) {
	for i := 1; i <= n+1; i++ {
		dis[i] = 0x3f3f3f3f
		vis[i] = 0
	}
	t = 0
	dis[s] = 0
	vis[s] = 1
	q[t] = s;
	t++
	for i := 0; i < t; i++ {
		u := q[i]
		for j := head[u]; j != 0; j = edge[j].next {
			v := edge[j].to
			if dis[v] > dis[u]+1 {
				dis[v] = dis[u] + 1
				q[t] = v
				t++
			}
		}
	}
}
func main() {
	n := ReadInt()
	m := ReadInt()
	for i := 1; i <= m; i++ {
		u := ReadInt()
		v := ReadInt()
		add(v, u)
		add1(u, v)
	}
	k := ReadInt()
	for i := 1; i <= k; i++ {
		a[i] = ReadInt()
	}
	bfs(a[k], n)
	for i := 2; i <= k; i++ {
		if dis[a[i]] != dis[a[i-1]]-1 {
			mi++
			ma++
		} else {
			var cnt3 int = 0
			for j := head1[a[i-1]]; j != 0; j = edge1[j].next {
				if dis[edge1[j].to] == dis[a[i-1]]-1 {
					cnt3++
				}
			}
			if cnt3 >= 2 {
				ma++
			}
		}
	}
	fmt.Println(mi, ma)
}

////////////////////////////////////

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

var out chan string
var in *bufio.Scanner
var outWg *sync.WaitGroup

func ReadString() string {
	in.Scan()
	return in.Text()
}
func ReadStringSlice(n int) []string {
	s := make([]string, n)
	for i := 0; i < n; i++ {
		s[i] = ReadString()
	}
	return s
}
func ReadInt() int {
	intStr := ReadString()
	i, _ := strconv.ParseInt(intStr, 10, 32)
	return int(i)
}
func ReadIntSlice(n int) []int {
	arr := make([]int, n)
	for i := 0; i < n; i++ {
		arr[i] = ReadInt()
	}
	return arr
}
func init() {
	//set input
	in = bufio.NewScanner(os.Stdin)
	in.Buffer(make([]byte, 1024), int(2e+5))
	in.Split(bufio.ScanWords)

	//set output
	out = make(chan string, 16)
	outWg = &sync.WaitGroup{}
	outWg.Add(1)

	writer := bufio.NewWriterSize(os.Stdout, int(2e+5))
	go func(write *bufio.Writer) {
		defer outWg.Done()
		defer write.Flush()

		for line := range out {
			write.WriteString(line + "\n")
		}
	}(writer)
}

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strconv"
)

var reader io.Reader
var scanner *bufio.Scanner

func Init(io io.Reader, max_token_size int) {
	reader = bufio.NewReader(io)
	scanner = bufio.NewScanner(reader)
	// max token size
	scanner.Split(bufio.ScanWords)
	scanner.Buffer([]byte{}, max_token_size)
}

func stderr(v ...interface{}) {
	fmt.Fprintln(os.Stderr, v...)
}

func die(v ...interface{}) {
	fmt.Fprintln(os.Stderr, v...)
	os.Exit(1)
}

func NextInt() int {
	bytes := NextBytes()
	i, err := Atoi(bytes)
	if err != nil {
		die(err)
	}
	return i
}

func NextBytes() []byte {
	if !scanner.Scan() {
		die(scanner.Err())
	}
	bytes := scanner.Bytes()
	copied := make([]byte, len(bytes))
	copy(copied, bytes)
	return copied
}

func Atoi(b []byte) (int, error) {
	neg := false
	if b[0] == '+' {
		b = b[1:]
	} else if b[0] == '-' {
		neg = true
		b = b[1:]
	}
	n := 0
	for _, v := range b {
		if v < '0' || v > '9' {
			return 0, strconv.ErrSyntax
		}
		n = n*10 + int(v-'0')
	}
	if neg {
		return -n, nil
	}
	return n, nil
}

func ExtendByteArray(a []byte, size int) []byte {
	if size <= len(a) {
		return a
	} else {
		return append(a, make([]byte, size-len(a))...)
	}
}

func ExtendIntArray(a []int, size int) []int {
	if size <= len(a) {
		return a
	} else {
		return append(a, make([]int, size-len(a))...)
	}
}

type Graph struct {
	n     int
	m     int
	edges int
	fst   []int
	nxt   []int
	end   []int
}

func (g *Graph) Add(a, b int) {
	g.nxt[g.edges] = g.fst[a]
	g.fst[a] = g.edges
	g.end[g.edges] = b
	g.edges++
}

func (g *Graph) Adjacent0(a int, fn func(b int)) {
	for u := g.fst[a]; u != -1; u = g.nxt[u] {
		if u%2 == 0 {
			fn(g.end[u])
		}
	}
}

func (g *Graph) Adjacent1(a int, fn func(b int)) {
	for u := g.fst[a]; u != -1; u = g.nxt[u] {
		if u%2 == 1 {
			fn(g.end[u])
		}
	}
}

func NewGraph(n, m int) *Graph {
	g := &Graph{n, m, 0, make([]int, n), make([]int, m), make([]int, m)}
	for i := 0; i < n; i++ {
		g.fst[i] = -1
	}
	return g
}

func main() {
	inf := os.Stdin
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()
	// inf, err := os.Open("a.in")
	// if err != nil {
	// 	die(err)
	// }
	// out, err := os.Create("a.out")
	// if err != nil {
	// 	die(err)
	// }
	// defer out.Close()
	Init(inf, 1000010)
	n, m := NextInt(), NextInt()
	g := NewGraph(n, 2*m)
	for i := 0; i < m; i++ {
		u, v := NextInt()-1, NextInt()-1
		g.Add(u, v)
		g.Add(v, u)
	}

	k := NextInt()
	p := make([]int, k)
	for i := 0; i < k; i++ {
		p[i] = NextInt() - 1
	}

	q := make([]int, n)
	was := make([]bool, n)
	d := make([]int, n)
	qh, qt := 0, 0
	q[qt] = p[k-1]
	was[p[k-1]] = true
	qt++
	for qh < qt {
		v := q[qh]
		qh++
		g.Adjacent1(v, func(to int) {
			if !was[to] {
				d[to] = d[v] + 1
				was[to] = true
				q[qt] = to
				qt++
			}
		})
	}

	var minValue, maxValue int
	for i := 0; i+1 < k; i++ {
		// stderr("check", i, p[i]+1, p[i+1]+1, d[p[i]], d[p[i+1]])
		if d[p[i]] != d[p[i+1]]+1 {

			minValue++
			maxValue++
		} else {
			found := false
			g.Adjacent0(p[i], func(to int) {
				if to != p[i+1] && d[p[i]] == d[to]+1 {
					found = true
				}
			})
			if found {
				maxValue++
			}
		}
	}
	fmt.Fprintln(out, minValue, maxValue)
}

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	r := bufio.NewReader(os.Stdin)

	var n, m int
	fmt.Fscanf(r, "%d %d\n", &n, &m)

	g := make(map[int][]int)
	rev := make(map[int][]int)
	for i := 0; i < m; i++ {
		var u, v int
		fmt.Fscanf(r, "%d %d\n", &u, &v)
		g[u] = append(g[u], v)
		rev[v] = append(rev[v], u)
	}

	var k int
	fmt.Fscanf(r, "%d\n", &k)

	p := make([]int, k)
	for i := 0; i < k; i++ {
		fmt.Fscanf(r, "%d", &p[i])
	}

	dist := bfs(rev, p[k-1])

	mini, maxi := 0, 0
	for i, u := range p {
		if i == k-2 {
			break
		}

		nxt := p[i+1]
		if dist[nxt] == dist[u]-1 {
			cc := 0
			for _, v := range g[u] {
				if dist[v] == dist[nxt] {
					cc++
				}
			}
			if cc > 1 {
				maxi++
			}
		} else {
			mini++
			maxi++
		}
	}

	fmt.Printf("%d %d\n", mini, maxi)
}

func bfs(g map[int][]int, s int) map[int]int {
	seen := make(map[int]bool)
	dist := make(map[int]int)

	var q []int

	q = append(q, s)
	dist[s] = 0
	seen[s] = true

	for len(q) > 0 {
		u := q[0]
		q = q[1:]

		for _, v := range g[u] {
			if !seen[v] {
				seen[v] = true
				dist[v] = 1 + dist[u]
				q = append(q, v)
			}
		}
	}

	return dist
}

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func CF1321D(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, v, w, k, min, ex int
	Fscan(in, &n, &m)
	g := make([][]int, n)
	rg := make([][]int, n)
	for ; m > 0; m-- {
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		rg[w] = append(rg[w], v)
	}
	Fscan(in, &k)
	path := make([]int, k)
	for i := range path {
		Fscan(in, &path[i])
		path[i]--
	}

	dep := make([]int, n)
	vis := make([]bool, n)
	vis[path[k-1]] = true
	q := []int{path[k-1]}
	for len(q) > 0 {
		v, q = q[0], q[1:]
		for _, w := range rg[v] {
			if !vis[w] {
				vis[w] = true
				dep[w] = dep[v] + 1
				q = append(q, w)
			}
		}
	}

	for i, v := range path[:k-1] {
		next := path[i+1]
		if dep[v] <= dep[next] {
			min++
			continue
		}
		for _, w := range g[v] {
			if w != next && dep[w] == dep[next] {
				ex++
				break
			}
		}
	}
	Fprint(out, min, min+ex)
}

func main() { CF1321D(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func CF1321D(_r io.Reader, _w io.Writer) {
	in := bufio.NewScanner(_r)
	in.Split(bufio.ScanWords)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	read := func() (x int) {
		in.Scan()
		for _, b := range in.Bytes() {
			x = x*10 + int(b-'0')
		}
		return
	}

	n, m := read(), read()
	g := make([][]int, n)
	rg := make([][]int, n)
	for ; m > 0; m-- {
		v, w := read()-1, read()-1
		g[v] = append(g[v], w)
		rg[w] = append(rg[w], v)
	}
	k := read()
	path := make([]int, k)
	for i := range path {
		path[i] = read() - 1
	}

	dep := make([]int, n)
	vis := make([]bool, n)
	vis[path[k-1]] = true
	q := []int{path[k-1]}
	for len(q) > 0 {
		var v int
		v, q = q[0], q[1:]
		for _, w := range rg[v] {
			if !vis[w] {
				vis[w] = true
				dep[w] = dep[v] + 1
				q = append(q, w)
			}
		}
	}

	min, ex := 0, 0
	for i, v := range path[:k-1] {
		next := path[i+1]
		if dep[v] <= dep[next] {
			min++
			continue
		}
		for _, w := range g[v] {
			if w != next && dep[w] == dep[next] {
				ex++
				break
			}
		}
	}
	Fprint(out, min, min+ex)
}

func main() { CF1321D(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, k int
	Fscan(in, &n, &m)
	g := make([][]int, n)
	rg := make([][]int, n)
	for i := 0; i < m; i++ {
		var v, w int
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		rg[w] = append(rg[w], v)
	}
	Fscan(in, &k)
	path := make([]int, k)
	for i := range path {
		Fscan(in, &path[i])
		path[i]--
	}
	st, end := path[0], path[k-1]

	// 最小：从终点看，每一步是否离终点更近了 dfswithdepth 相邻dep之差为1
	// 最大：

	vis := make([]bool, n)
	vis[st] = true
	dep := make([]int, n)
	type pair struct{ v, dep int }
	queue := []pair{{st, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		dep[p.v] = p.dep
		for _, w := range g[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	vis = make([]bool, n)
	vis[end] = true
	rdep := make([]int, n)
	queue = []pair{{end, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		rdep[p.v] = p.dep
		for _, w := range rg[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	minAns := 0
	for i := 1; i < k; i++ {
		v, last := path[i], path[i-1]
		if rdep[v]-rdep[last] >= 0 {
			minAns++
		}
	}

	maxAns := 0
	for i := 0; i < k-1; i++ {
		v := path[i]
		next := path[i+1]
		if rdep[v]-rdep[next] <= 0 {
			maxAns++
			continue
		}
		for _, w := range g[v] {
			if w != next && rdep[w] == rdep[next] {
				maxAns++
				break
			}
		}
	}

	Fprintln(out, minAns, maxAns)
}

func main() { run(os.Stdin, os.Stdout) }

/*
URL:
https://codeforces.com/problemset/problem/1320/B
*/

package main

import (
	"bufio"
	"container/heap"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := ReadString()
//i := ReadInt()
//X := ReadIntSlice(n)
//S := ReadRuneSlice()
//a := ReadFloat64()
//A := ReadFloat64Slice(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*******************************************************************/

const (
	// General purpose
	MOD          = 1000000000 + 7
	ALPHABET_NUM = 26
	INF_INT64    = math.MaxInt64
	INF_BIT60    = 1 << 60
	INF_INT32    = math.MaxInt32
	INF_BIT30    = 1 << 30
	NIL          = -1

	// for dijkstra, prim, and so on
	WHITE = 0
	GRAY  = 1
	BLACK = 2
)

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	ReadString = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

var (
	n, m int
	k    int
	P    []int

	G [200000 + 50][]Edge

	cnts [200000 + 50]int
)

func main() {
	n, m = ReadInt2()
	for i := 0; i < m; i++ {
		u, v := ReadInt2()
		u--
		v--

		// 逆向きに貼る
		G[v] = append(G[v], Edge{to: u, cost: 1})
	}
	k = ReadInt()
	P = ReadIntSlice(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	dp, _ := dijkstra(P[k-1], n, G[:n])
	PrintfDebug("dp: %v\n", dp)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]
		A := dp[cid] == dp[nid]+1
		cnt := cnts[dp[cid]-1]
		if A {
			cnt--
		}
		B := cnt > 0

		if A && B {
			maxi++
		} else if A && !B {
		} else if !A && B {
			mini++
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

type (
	Edge struct {
		to   int
		cost int
	}
	Vertex struct {
		pri int
		id  int
	}
)

const INF_DIJK = 1 << 30

func dijkstra(sid, n int, AG [][]Edge) (dp, parents []int) {
	dp = make([]int, n)
	parents = make([]int, n)
	colors := make([]int, n)
	for i := 0; i < n; i++ {
		dp[i] = INF_DIJK
		colors[i], parents[i] = WHITE, -1
	}

	temp := make(VertexPQ, 0, 100000+5)
	pq := &temp
	heap.Init(pq)
	heap.Push(pq, &Vertex{pri: 0, id: sid})
	dp[sid] = 0
	colors[sid] = GRAY

	for pq.Len() > 0 {
		pop := heap.Pop(pq).(*Vertex)

		colors[pop.id] = BLACK

		if pop.pri > dp[pop.id] {
			continue
		}

		for _, e := range AG[pop.id] {
			if colors[e.to] == BLACK {
				continue
			}

			if dp[e.to] > dp[pop.id]+e.cost {
				dp[e.to] = dp[pop.id] + e.cost
				heap.Push(pq, &Vertex{pri: dp[e.to], id: e.to})
				colors[e.to], parents[e.to] = GRAY, pop.id
			}
		}
	}

	return dp, parents
}

type VertexPQ []*Vertex

func (pq VertexPQ) Len() int           { return len(pq) }
func (pq VertexPQ) Less(i, j int) bool { return pq[i].pri < pq[j].pri } // <: ASC, >: DESC
func (pq VertexPQ) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}
func (pq *VertexPQ) Push(x interface{}) {
	item := x.(*Vertex)
	*pq = append(*pq, item)
}
func (pq *VertexPQ) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

// how to use
// temp := make(VertexPQ, 0, 100000+1)
// pq := &temp
// heap.Init(pq)
// heap.Push(pq, &Vertex{pri: intValue})
// popped := heap.Pop(pq).(*Vertex)

/*******************************************************************/

/*********** I/O ***********/

var (
	// ReadString returns a WORD string.
	ReadString func() string
	stdout     *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// ReadInt returns an integer.
func ReadInt() int {
	return int(readInt64())
}
func ReadInt2() (int, int) {
	return int(readInt64()), int(readInt64())
}
func ReadInt3() (int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64())
}
func ReadInt4() (int, int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64()), int(readInt64())
}

// ReadInt64 returns as integer as int64.
func ReadInt64() int64 {
	return readInt64()
}
func ReadInt64_2() (int64, int64) {
	return readInt64(), readInt64()
}
func ReadInt64_3() (int64, int64, int64) {
	return readInt64(), readInt64(), readInt64()
}
func ReadInt64_4() (int64, int64, int64, int64) {
	return readInt64(), readInt64(), readInt64(), readInt64()
}

func readInt64() int64 {
	i, err := strconv.ParseInt(ReadString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// ReadIntSlice returns an integer slice that has n integers.
func ReadIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt()
	}
	return b
}

// ReadInt64Slice returns as int64 slice that has n integers.
func ReadInt64Slice(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt64()
	}
	return b
}

// ReadFloat64 returns an float64.
func ReadFloat64() float64 {
	return float64(readFloat64())
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(ReadString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func ReadFloat64Slice(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadFloat64()
	}
	return b
}

// ReadRuneSlice returns a rune slice.
func ReadRuneSlice() []rune {
	return []rune(ReadString())
}

/*********** Debugging ***********/

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

// Strtoi is a wrapper of strconv.Atoi().
// If strconv.Atoi() returns an error, Strtoi calls panic.
func Strtoi(s string) int {
	if i, err := strconv.Atoi(s); err != nil {
		panic(errors.New("[argument error]: Strtoi only accepts integer string"))
	} else {
		return i
	}
}

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintfDebug is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func PrintfDebug(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// PrintfBufStdout is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func PrintfBufStdout(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*
URL:
https://codeforces.com/problemset/problem/1320/B
*/

package main

import (
	"bufio"
	"container/heap"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := ReadString()
//i := ReadInt()
//X := ReadIntSlice(n)
//S := ReadRuneSlice()
//a := ReadFloat64()
//A := ReadFloat64Slice(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*******************************************************************/

const (
	// General purpose
	MOD          = 1000000000 + 7
	ALPHABET_NUM = 26
	INF_INT64    = math.MaxInt64
	INF_BIT60    = 1 << 60
	INF_INT32    = math.MaxInt32
	INF_BIT30    = 1 << 30
	NIL          = -1

	// for dijkstra, prim, and so on
	WHITE = 0
	GRAY  = 1
	BLACK = 2
)

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	ReadString = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

var (
	n, m int
	k    int
	P    []int

	G [200000 + 50][]Edge

	cnts [200000 + 50]int
)

func main() {
	n, m = ReadInt2()
	for i := 0; i < m; i++ {
		u, v := ReadInt2()
		u--
		v--

		// 逆向きに貼る
		G[v] = append(G[v], Edge{to: u, cost: 1})
	}
	k = ReadInt()
	P = ReadIntSlice(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	dp, _ := dijkstra(P[k-1], n, G[:n])
	PrintfDebug("dp: %v\n", dp)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]

		A := dp[cid] == dp[nid]+1

		cnt := cnts[dp[cid]-1]
		// if A {
		// 	cnt--
		// }
		cnt--
		B := cnt > 0

		if A && B {
			maxi++
		} else if A && !B {
		} else if !A && B {
			mini++
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

type (
	Edge struct {
		to   int
		cost int
	}
	Vertex struct {
		pri int
		id  int
	}
)

const INF_DIJK = 1 << 30

func dijkstra(sid, n int, AG [][]Edge) (dp, parents []int) {
	dp = make([]int, n)
	parents = make([]int, n)
	colors := make([]int, n)
	for i := 0; i < n; i++ {
		dp[i] = INF_DIJK
		colors[i], parents[i] = WHITE, -1
	}

	temp := make(VertexPQ, 0, 100000+5)
	pq := &temp
	heap.Init(pq)
	heap.Push(pq, &Vertex{pri: 0, id: sid})
	dp[sid] = 0
	colors[sid] = GRAY

	for pq.Len() > 0 {
		pop := heap.Pop(pq).(*Vertex)

		colors[pop.id] = BLACK

		if pop.pri > dp[pop.id] {
			continue
		}

		for _, e := range AG[pop.id] {
			if colors[e.to] == BLACK {
				continue
			}

			if dp[e.to] > dp[pop.id]+e.cost {
				dp[e.to] = dp[pop.id] + e.cost
				heap.Push(pq, &Vertex{pri: dp[e.to], id: e.to})
				colors[e.to], parents[e.to] = GRAY, pop.id
			}
		}
	}

	return dp, parents
}

type VertexPQ []*Vertex

func (pq VertexPQ) Len() int           { return len(pq) }
func (pq VertexPQ) Less(i, j int) bool { return pq[i].pri < pq[j].pri } // <: ASC, >: DESC
func (pq VertexPQ) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}
func (pq *VertexPQ) Push(x interface{}) {
	item := x.(*Vertex)
	*pq = append(*pq, item)
}
func (pq *VertexPQ) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

// how to use
// temp := make(VertexPQ, 0, 100000+1)
// pq := &temp
// heap.Init(pq)
// heap.Push(pq, &Vertex{pri: intValue})
// popped := heap.Pop(pq).(*Vertex)

/*******************************************************************/

/*********** I/O ***********/

var (
	// ReadString returns a WORD string.
	ReadString func() string
	stdout     *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// ReadInt returns an integer.
func ReadInt() int {
	return int(readInt64())
}
func ReadInt2() (int, int) {
	return int(readInt64()), int(readInt64())
}
func ReadInt3() (int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64())
}
func ReadInt4() (int, int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64()), int(readInt64())
}

// ReadInt64 returns as integer as int64.
func ReadInt64() int64 {
	return readInt64()
}
func ReadInt64_2() (int64, int64) {
	return readInt64(), readInt64()
}
func ReadInt64_3() (int64, int64, int64) {
	return readInt64(), readInt64(), readInt64()
}
func ReadInt64_4() (int64, int64, int64, int64) {
	return readInt64(), readInt64(), readInt64(), readInt64()
}

func readInt64() int64 {
	i, err := strconv.ParseInt(ReadString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// ReadIntSlice returns an integer slice that has n integers.
func ReadIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt()
	}
	return b
}

// ReadInt64Slice returns as int64 slice that has n integers.
func ReadInt64Slice(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt64()
	}
	return b
}

// ReadFloat64 returns an float64.
func ReadFloat64() float64 {
	return float64(readFloat64())
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(ReadString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func ReadFloat64Slice(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadFloat64()
	}
	return b
}

// ReadRuneSlice returns a rune slice.
func ReadRuneSlice() []rune {
	return []rune(ReadString())
}

/*********** Debugging ***********/

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

// Strtoi is a wrapper of strconv.Atoi().
// If strconv.Atoi() returns an error, Strtoi calls panic.
func Strtoi(s string) int {
	if i, err := strconv.Atoi(s); err != nil {
		panic(errors.New("[argument error]: Strtoi only accepts integer string"))
	} else {
		return i
	}
}

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintfDebug is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func PrintfDebug(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// PrintfBufStdout is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func PrintfBufStdout(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*
URL:
https://codeforces.com/problemset/problem/1320/B
*/

package main

import (
	"bufio"
	"container/heap"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := ReadString()
//i := ReadInt()
//X := ReadIntSlice(n)
//S := ReadRuneSlice()
//a := ReadFloat64()
//A := ReadFloat64Slice(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*******************************************************************/

const (
	// General purpose
	MOD          = 1000000000 + 7
	ALPHABET_NUM = 26
	INF_INT64    = math.MaxInt64
	INF_BIT60    = 1 << 60
	INF_INT32    = math.MaxInt32
	INF_BIT30    = 1 << 30
	NIL          = -1

	// for dijkstra, prim, and so on
	WHITE = 0
	GRAY  = 1
	BLACK = 2
)

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	ReadString = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

var (
	n, m int
	k    int
	P    []int

	G [200000 + 50][]Edge

	cnts [200000 + 50]int
)

func main() {
	n, m = ReadInt2()
	for i := 0; i < m; i++ {
		u, v := ReadInt2()
		u--
		v--

		// 逆向きに貼る
		G[v] = append(G[v], Edge{to: u, cost: 1})
	}
	k = ReadInt()
	P = ReadIntSlice(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	dp, _ := dijkstra(P[k-1], n, G[:n])
	PrintfDebug("dp: %v\n", dp)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]

		// A := dp[cid] == dp[nid]+1

		// cnt := cnts[dp[cid]-1]
		// if A {
		// 	cnt--
		// }
		// B := cnt > 0

		// if A && B {
		// 	maxi++
		// } else if A && !B {
		// } else if !A && B {
		// 	mini++
		// 	maxi++
		// }

		// by tutorial...
		if dp[cid]-1 < dp[nid] {
			mini++
			maxi++
			continue
		}

		A := dp[cid] == dp[nid]+1
		cnt := cnts[dp[cid]-1]
		if A {
			cnt--
		}
		B := cnt > 0
		if A && B {
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

type (
	Edge struct {
		to   int
		cost int
	}
	Vertex struct {
		pri int
		id  int
	}
)

const INF_DIJK = 1 << 30

func dijkstra(sid, n int, AG [][]Edge) (dp, parents []int) {
	dp = make([]int, n)
	parents = make([]int, n)
	colors := make([]int, n)
	for i := 0; i < n; i++ {
		dp[i] = INF_DIJK
		colors[i], parents[i] = WHITE, -1
	}

	temp := make(VertexPQ, 0, 100000+5)
	pq := &temp
	heap.Init(pq)
	heap.Push(pq, &Vertex{pri: 0, id: sid})
	dp[sid] = 0
	colors[sid] = GRAY

	for pq.Len() > 0 {
		pop := heap.Pop(pq).(*Vertex)

		colors[pop.id] = BLACK

		if pop.pri > dp[pop.id] {
			continue
		}

		for _, e := range AG[pop.id] {
			if colors[e.to] == BLACK {
				continue
			}

			if dp[e.to] > dp[pop.id]+e.cost {
				dp[e.to] = dp[pop.id] + e.cost
				heap.Push(pq, &Vertex{pri: dp[e.to], id: e.to})
				colors[e.to], parents[e.to] = GRAY, pop.id
			}
		}
	}

	return dp, parents
}

type VertexPQ []*Vertex

func (pq VertexPQ) Len() int           { return len(pq) }
func (pq VertexPQ) Less(i, j int) bool { return pq[i].pri < pq[j].pri } // <: ASC, >: DESC
func (pq VertexPQ) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}
func (pq *VertexPQ) Push(x interface{}) {
	item := x.(*Vertex)
	*pq = append(*pq, item)
}
func (pq *VertexPQ) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

// how to use
// temp := make(VertexPQ, 0, 100000+1)
// pq := &temp
// heap.Init(pq)
// heap.Push(pq, &Vertex{pri: intValue})
// popped := heap.Pop(pq).(*Vertex)

/*******************************************************************/

/*********** I/O ***********/

var (
	// ReadString returns a WORD string.
	ReadString func() string
	stdout     *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// ReadInt returns an integer.
func ReadInt() int {
	return int(readInt64())
}
func ReadInt2() (int, int) {
	return int(readInt64()), int(readInt64())
}
func ReadInt3() (int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64())
}
func ReadInt4() (int, int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64()), int(readInt64())
}

// ReadInt64 returns as integer as int64.
func ReadInt64() int64 {
	return readInt64()
}
func ReadInt64_2() (int64, int64) {
	return readInt64(), readInt64()
}
func ReadInt64_3() (int64, int64, int64) {
	return readInt64(), readInt64(), readInt64()
}
func ReadInt64_4() (int64, int64, int64, int64) {
	return readInt64(), readInt64(), readInt64(), readInt64()
}

func readInt64() int64 {
	i, err := strconv.ParseInt(ReadString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// ReadIntSlice returns an integer slice that has n integers.
func ReadIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt()
	}
	return b
}

// ReadInt64Slice returns as int64 slice that has n integers.
func ReadInt64Slice(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt64()
	}
	return b
}

// ReadFloat64 returns an float64.
func ReadFloat64() float64 {
	return float64(readFloat64())
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(ReadString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func ReadFloat64Slice(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadFloat64()
	}
	return b
}

// ReadRuneSlice returns a rune slice.
func ReadRuneSlice() []rune {
	return []rune(ReadString())
}

/*********** Debugging ***********/

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

// Strtoi is a wrapper of strconv.Atoi().
// If strconv.Atoi() returns an error, Strtoi calls panic.
func Strtoi(s string) int {
	if i, err := strconv.Atoi(s); err != nil {
		panic(errors.New("[argument error]: Strtoi only accepts integer string"))
	} else {
		return i
	}
}

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintfDebug is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func PrintfDebug(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// PrintfBufStdout is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func PrintfBufStdout(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*
URL:
https://codeforces.com/problemset/problem/1320/B
*/

package main

import (
	"bufio"
	"container/heap"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := ReadString()
//i := ReadInt()
//X := ReadIntSlice(n)
//S := ReadRuneSlice()
//a := ReadFloat64()
//A := ReadFloat64Slice(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*******************************************************************/

const (
	// General purpose
	MOD          = 1000000000 + 7
	ALPHABET_NUM = 26
	INF_INT64    = math.MaxInt64
	INF_BIT60    = 1 << 60
	INF_INT32    = math.MaxInt32
	INF_BIT30    = 1 << 30
	NIL          = -1

	// for dijkstra, prim, and so on
	WHITE = 0
	GRAY  = 1
	BLACK = 2
)

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	ReadString = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

var (
	n, m int
	k    int
	P    []int

	G [200000 + 50][]Edge

	cnts [200000 + 50]int
)

func main() {
	n, m = ReadInt2()
	for i := 0; i < m; i++ {
		u, v := ReadInt2()
		u--
		v--

		// 逆向きに貼る
		G[v] = append(G[v], Edge{to: u, cost: 1})
	}
	k = ReadInt()
	P = ReadIntSlice(k)
	for i := 0; i < k; i++ {
		P[i]--
	}

	dp, _ := dijkstra(P[k-1], n, G[:n])
	PrintfDebug("dp: %v\n", dp)

	for i := 0; i < n; i++ {
		cnts[dp[i]]++
	}

	mini, maxi := 0, 0
	for i := 0; i < k-1; i++ {
		cid, nid := P[i], P[i+1]

		// A := dp[cid] == dp[nid]+1

		// cnt := cnts[dp[cid]-1]
		// if A {
		// 	cnt--
		// }
		// B := cnt > 0

		// if A && B {
		// 	maxi++
		// } else if A && !B {
		// } else if !A && B {
		// 	mini++
		// 	maxi++
		// }

		// by tutorial...
		if dp[cid]-1 < dp[nid] {
			mini++
			maxi++
			continue
		}

		A := dp[cid] == dp[nid]+1
		cnt := cnts[dp[cid]-1]
		if A {
			cnt--
		}
		B := cnt > 0
		if B {
			maxi++
		}
	}

	fmt.Println(mini, maxi)
}

type (
	Edge struct {
		to   int
		cost int
	}
	Vertex struct {
		pri int
		id  int
	}
)

const INF_DIJK = 1 << 30

func dijkstra(sid, n int, AG [][]Edge) (dp, parents []int) {
	dp = make([]int, n)
	parents = make([]int, n)
	colors := make([]int, n)
	for i := 0; i < n; i++ {
		dp[i] = INF_DIJK
		colors[i], parents[i] = WHITE, -1
	}

	temp := make(VertexPQ, 0, 100000+5)
	pq := &temp
	heap.Init(pq)
	heap.Push(pq, &Vertex{pri: 0, id: sid})
	dp[sid] = 0
	colors[sid] = GRAY

	for pq.Len() > 0 {
		pop := heap.Pop(pq).(*Vertex)

		colors[pop.id] = BLACK

		if pop.pri > dp[pop.id] {
			continue
		}

		for _, e := range AG[pop.id] {
			if colors[e.to] == BLACK {
				continue
			}

			if dp[e.to] > dp[pop.id]+e.cost {
				dp[e.to] = dp[pop.id] + e.cost
				heap.Push(pq, &Vertex{pri: dp[e.to], id: e.to})
				colors[e.to], parents[e.to] = GRAY, pop.id
			}
		}
	}

	return dp, parents
}

type VertexPQ []*Vertex

func (pq VertexPQ) Len() int           { return len(pq) }
func (pq VertexPQ) Less(i, j int) bool { return pq[i].pri < pq[j].pri } // <: ASC, >: DESC
func (pq VertexPQ) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}
func (pq *VertexPQ) Push(x interface{}) {
	item := x.(*Vertex)
	*pq = append(*pq, item)
}
func (pq *VertexPQ) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

// how to use
// temp := make(VertexPQ, 0, 100000+1)
// pq := &temp
// heap.Init(pq)
// heap.Push(pq, &Vertex{pri: intValue})
// popped := heap.Pop(pq).(*Vertex)

/*******************************************************************/

/*********** I/O ***********/

var (
	// ReadString returns a WORD string.
	ReadString func() string
	stdout     *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// ReadInt returns an integer.
func ReadInt() int {
	return int(readInt64())
}
func ReadInt2() (int, int) {
	return int(readInt64()), int(readInt64())
}
func ReadInt3() (int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64())
}
func ReadInt4() (int, int, int, int) {
	return int(readInt64()), int(readInt64()), int(readInt64()), int(readInt64())
}

// ReadInt64 returns as integer as int64.
func ReadInt64() int64 {
	return readInt64()
}
func ReadInt64_2() (int64, int64) {
	return readInt64(), readInt64()
}
func ReadInt64_3() (int64, int64, int64) {
	return readInt64(), readInt64(), readInt64()
}
func ReadInt64_4() (int64, int64, int64, int64) {
	return readInt64(), readInt64(), readInt64(), readInt64()
}

func readInt64() int64 {
	i, err := strconv.ParseInt(ReadString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// ReadIntSlice returns an integer slice that has n integers.
func ReadIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt()
	}
	return b
}

// ReadInt64Slice returns as int64 slice that has n integers.
func ReadInt64Slice(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadInt64()
	}
	return b
}

// ReadFloat64 returns an float64.
func ReadFloat64() float64 {
	return float64(readFloat64())
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(ReadString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func ReadFloat64Slice(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = ReadFloat64()
	}
	return b
}

// ReadRuneSlice returns a rune slice.
func ReadRuneSlice() []rune {
	return []rune(ReadString())
}

/*********** Debugging ***********/

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

// Strtoi is a wrapper of strconv.Atoi().
// If strconv.Atoi() returns an error, Strtoi calls panic.
func Strtoi(s string) int {
	if i, err := strconv.Atoi(s); err != nil {
		panic(errors.New("[argument error]: Strtoi only accepts integer string"))
	} else {
		return i
	}
}

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintfDebug is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func PrintfDebug(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// PrintfBufStdout is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func PrintfBufStdout(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, k int
	Fscan(in, &n, &m)
	g := make([][]int, n)
	rg := make([][]int, n)
	for i := 0; i < m; i++ {
		var v, w int
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		rg[w] = append(rg[w], v)
	}
	Fscan(in, &k)
	path := make([]int, k)
	for i := range path {
		Fscan(in, &path[i])
		path[i]--
	}
	if k == 2 {
		Fprintln(out, 0, 0)
		return
	}
	st, end := path[0], path[k-1]

	// 最小：从终点看，每一步是否离终点更近了 dfswithdepth 相邻dep之差为1
	// 最大：

	vis := make([]bool, n)
	vis[st] = true
	dep := make([]int, n)
	type pair struct{ v, dep int }
	queue := []pair{{st, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		dep[p.v] = p.dep
		for _, w := range g[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	vis = make([]bool, n)
	vis[end] = true
	rdep := make([]int, n)
	queue = []pair{{end, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		rdep[p.v] = p.dep
		for _, w := range rg[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	minAns := 0
	for i := 1; i < k; i++ {
		v, last := path[i], path[i-1]
		if rdep[v]-rdep[last] >= 0 {
			minAns++
		}
	}

	maxAns := 0
	for i := 0; i < k-1; i++ {
		v := path[i]
		next := path[i+1]
		if rdep[v]-rdep[next] <= 0 {
			maxAns++
			continue
		}
		for _, w := range g[v] {
			if w != next && dep[w] == dep[next] {
				maxAns++
				continue
			}
		}
	}

	Fprintln(out, minAns, maxAns)
}

func main() { run(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, k int
	Fscan(in, &n, &m)
	g := make([][]int, n)
	rg := make([][]int, n)
	for i := 0; i < m; i++ {
		var v, w int
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		rg[w] = append(rg[w], v)
	}
	Fscan(in, &k)
	path := make([]int, k)
	for i := range path {
		Fscan(in, &path[i])
		path[i]--
	}
	if k == 2 {
		Fprintln(out, 0, 0)
		return
	}
	st, end := path[0], path[k-1]

	// 最小：从终点看，每一步是否离终点更近了 dfswithdepth 相邻dep之差为1
	// 最大：

	vis := make([]bool, n)
	vis[st] = true
	dep := make([]int, n)
	type pair struct{ v, dep int }
	queue := []pair{{st, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		dep[p.v] = p.dep
		for _, w := range g[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	vis = make([]bool, n)
	vis[end] = true
	rdep := make([]int, n)
	queue = []pair{{end, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		rdep[p.v] = p.dep
		for _, w := range rg[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	minAns := 0
	for i := 1; i < k; i++ {
		v, last := path[i], path[i-1]
		if rdep[v]-rdep[last] >= 0 {
			minAns++
		}
	}

	maxAns := 0
	for i := 0; i < k-1; i++ {
		v := path[i]
		next := path[i+1]
		if rdep[v]-rdep[next] <= 0 {
			maxAns++
			continue
		}
		for _, w := range g[v] {
			if w != next && rdep[w] == rdep[next] {
				maxAns++
				continue
			}
		}
	}

	Fprintln(out, minAns, maxAns)
}

func main() { run(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n, m, k int
	Fscan(in, &n, &m)
	g := make([][]int, n)
	rg := make([][]int, n)
	for i := 0; i < m; i++ {
		var v, w int
		Fscan(in, &v, &w)
		v--
		w--
		g[v] = append(g[v], w)
		rg[w] = append(rg[w], v)
	}
	Fscan(in, &k)
	path := make([]int, k)
	for i := range path {
		Fscan(in, &path[i])
		path[i]--
	}
	st, end := path[0], path[k-1]

	// 最小：从终点看，每一步是否离终点更近了 dfswithdepth 相邻dep之差为1
	// 最大：

	vis := make([]bool, n)
	vis[st] = true
	dep := make([]int, n)
	type pair struct{ v, dep int }
	queue := []pair{{st, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		dep[p.v] = p.dep
		for _, w := range g[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	vis = make([]bool, n)
	vis[end] = true
	rdep := make([]int, n)
	queue = []pair{{end, 0}}
	for len(queue) > 0 {
		var p pair
		p, queue = queue[0], queue[1:]
		rdep[p.v] = p.dep
		for _, w := range rg[p.v] {
			if !vis[w] {
				vis[w] = true
				queue = append(queue, pair{w, p.dep + 1})
			}
		}
	}

	minAns := 0
	for i := 1; i < k; i++ {
		v, last := path[i], path[i-1]
		if rdep[v]-rdep[last] >= 0 {
			minAns++
		}
	}

	maxAns := 0
	for i := 0; i < k-1; i++ {
		v := path[i]
		next := path[i+1]
		if rdep[v]-rdep[next] <= 0 {
			maxAns++
			continue
		}
		for _, w := range g[v] {
			if w != next && dep[w] == dep[next] {
				maxAns++
				break
			}
		}
	}

	Fprintln(out, minAns, maxAns)
}

func main() { run(os.Stdin, os.Stdout) }


It's holiday. Mashmokh and his boss, Bimokh, are playing a game invented by Mashmokh. In this game Mashmokh writes sequence of n distinct integers on the board. Then Bimokh makes several (possibly zero) moves. On the first move he removes the first and the second integer from from the board, on the second move he removes the first and the second integer of the remaining sequence from the board, and so on. Bimokh stops when the board contains less than two numbers. When Bimokh removes numbers x and y from the board, he gets gcd(x, y) points. At the beginning of the game Bimokh has zero points.Mashmokh wants to win in the game. For this reason he wants his boss to get exactly k points in total. But the guy doesn't know how choose the initial sequence in the right way. Please, help him. Find n distinct integers a1, a2, ..., an such that his boss will score exactly k points. Also Mashmokh can't memorize too huge numbers. Therefore each of these integers must be at most 109.

The first line of input contains two space-separated integers n, k (1 ≤ n ≤ 105; 0 ≤ k ≤ 108).

If such sequence doesn't exist output -1 otherwise output n distinct space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109).

Notegcd(x, y) is greatest common divisor of x and y.

package main

import (
	"fmt"
)

var (
	primes = make([]int, 0, 100000)
	composite = make([]bool, 1300000)
)

func main() {
	for i := 2; len(primes) != cap(primes); i++ {
		if !composite[i] {
			primes = append(primes, i)
			for j := i * 2; j < len(composite); j += i {
				composite[j] = true
			}
		}
	}
	var n, k int
	fmt.Scan(&n, &k)
	if n / 2 > k {
		fmt.Println(-1)
		return
	}
	if n == 1 {
		if k == 0 {
			fmt.Println(1)
		} else {
			fmt.Println(-1)
		}
		return
	}
	x := k - (n / 2 - 1)
	fmt.Print(x * 2, x * 3)
	if x == 1 {
		primes = primes[2:]
	}
	for _, p := range primes[:n-2] {
		fmt.Print(" ", p)
	}
	fmt.Println()
}

package main
import (
	"fmt"
	//"sort"
	//"unicode/utf8"
)
func main() {
	var n,k int
	fmt.Scan(&n,&k)
	if n==1 && k>0 || k<n/2 {
		fmt.Println("-1")
	} else if n==1 && k==0 {
		fmt.Println("1")
	} else {
		if k==n/2 {
			for i:=1;i<n;i++ {
				fmt.Print(i," ")
			}
			fmt.Println(n)
		} else {
			t:=k-n/2+1
			fmt.Print(t," ",t*2)
			for i:=t*2+1;i<t*2+n-1;i++ {
				fmt.Print(" ",i)
			}
			fmt.Println()
		}
	}

}

package main

import (
    "fmt"
    "bufio"
    "os"
    "strconv"
)

func main() {
    writer := bufio.NewWriter(os.Stdout)
    var n,k int
    fmt.Scan(&n,&k)
    if (n/2 > k) || ((n < 2) && (k > 0)) {
        writer.WriteString("-1\n")
    } else if k == 0 {
        writer.WriteString("1\n")
    } else if (n/2) == k {
        for i := 1; i <= n; i++ {
            writer.WriteString(strconv.Itoa(i))
            if i == n { writer.WriteRune('\n') } else { writer.WriteRune(' ') }
        }
    } else {
        a := k-((n/2)-1)
        writer.WriteString(strconv.Itoa(a)+" "+strconv.Itoa(a*2))
        for i := 1; i <= (n-2); i++ {
            writer.WriteString(" "+strconv.Itoa(i+200000000))
        }
        writer.WriteRune('\n')
    }
    writer.Flush()
}

// 414A-mic
package main

import (
    "fmt"
)

func main() {
    var n, k int
    fmt.Scan(&n, &k)
    t := n/2 - 1
    u := k - t
    if n == 1 {
        if k == 0 {
            fmt.Print("1")
        } else {
            fmt.Print(-1)
        }
        return
    }
    if u < 1 {
        fmt.Print("-1")
        return
    }

    fmt.Print(u)
    fmt.Print(" ")
    fmt.Print(2 * u)
    cou := 1
    for i := 0; i < t; i++ {
        for cou == u || cou+1 == u || cou+1 == 2*u || cou == 2*u {
            cou += 2
        }
        fmt.Print(" ")
        fmt.Print(cou)
        fmt.Print(" ")
        fmt.Print(cou + 1)
        cou += 2
    }
    if n%2 == 1 {
        if cou == u {
            cou++
        }
        if cou == 2*u {
            cou++
        }
        fmt.Print(" ")
        fmt.Print(cou)
    }
    fmt.Println()
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Io struct {
	reader    *bufio.Reader
	writer    *bufio.Writer
	tokens    []string
	nextToken int
}

func NewIo() *Io {
	return &Io{
		reader: bufio.NewReader(os.Stdin),
		writer: bufio.NewWriter(os.Stdout),
	}
}

func (io *Io) Flush() {
	err := io.writer.Flush()
	if err != nil {
		panic(err)
	}
}

func (io *Io) NextLine() string {
	var buffer []byte
	for {
		line, isPrefix, err := io.reader.ReadLine()
		if err != nil {
			panic(err)
		}
		buffer = append(buffer, line...)
		if !isPrefix {
			break
		}
	}
	return string(buffer)
}

func (io *Io) Next() string {
	for io.nextToken >= len(io.tokens) {
		line := io.NextLine()
		io.tokens = strings.Fields(line)
		io.nextToken = 0
	}
	r := io.tokens[io.nextToken]
	io.nextToken++
	return r
}

func (io *Io) NextInt() int {
	i, err := strconv.Atoi(io.Next())
	if err != nil {
		panic(err)
	}
	return i
}

func (io *Io) NextLong() int64 {
	i, err := strconv.ParseInt(io.Next(), 10, 64)
	if err != nil {
		panic(err)
	}
	return i
}

func (io *Io) NextDouble() float64 {
	i, err := strconv.ParseFloat(io.Next(), 64)
	if err != nil {
		panic(err)
	}
	return i
}

func (io *Io) PrintLn(a ...interface{}) {
	fmt.Fprintln(io.writer, a...)
}

func (io *Io) Printf(format string, a ...interface{}) {
	fmt.Fprintf(io.writer, format, a...)
}

func (io *Io) PrintIntLn(a []int) {
	b := []interface{}{}
	for _, x := range a {
		b = append(b, x)
	}
	io.PrintLn(b...)
}

func (io *Io) PrintStringLn(a []string) {
	b := []interface{}{}
	for _, x := range a {
		b = append(b, x)
	}
	io.PrintLn(b...)
}

func Log(name string, value interface{}) {
	fmt.Fprintf(os.Stderr, "%s=%+v\n", name, value)
}

func intMin(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func main() {
	io := NewIo()
	defer io.Flush()
	N := io.NextInt()
	K := io.NextInt()
	M := N / 2
	if K < M {
		io.PrintLn(-1)
	} else if N == 1 {
		if K == 0 {
			io.PrintLn(1)
		} else {
			io.PrintLn(-1)
		}
	} else {
		A := make([]int, N)
		used := make(map[int]bool)
		//Log("M", M)
		A[0] = K - (M - 1)
		A[1] = 2 * A[0]
		used[A[0]] = true
		used[A[1]] = true
		last := 0
		for i := 0; i < M - 1; i++ {
			for {
				_, ok := used[last + 1]
				_, ok2 := used[last + 2]
				if ok || ok2 {
					last += 2
				} else {
					break
				}
			}
			A[2 + 2 * i] = last + 1
			A[2 + 2 * i + 1] = last + 2
			last = last + 2
		}
		if N % 2 == 1 {
			for {
				_, ok := used[last + 1]
				if ok {
					last++
				} else {
					break
				}
			}
			A[N - 1] = last + 1
		}
		io.PrintIntLn(A)
	}
}

package main

import (
	"fmt"
)

func main() {
	var n, k int
	fmt.Scan(&n, &k)
	if n / 2 > k {
		fmt.Println(-1)
		return
	}
	x := k - (n / 2 - 1)
	fmt.Print(x, x)
	for i := 2; i < n; i++ {
		fmt.Print(" ", 1)
	}
	fmt.Println()
}

package main
import (
	"fmt"
	//"sort"
	//"unicode/utf8"
)
func main() {
	var n,k int
	fmt.Scan(&n,&k)
	hit:=n/2
	if hit==0 && k==0 {
		fmt.Print("1")
	} else if hit>k || hit==0 {
		fmt.Print("-1")
	} else {
		x:=k-(hit-1)
		fmt.Print(x," ",x*k)
		x=x*k+1
		n=n-2
		for j:=0;j<n;j++ {
			fmt.Print(" ",x)
			x++
		}
		fmt.Print("")
	}

}

package main

import (
    "fmt"
    "bufio"
    "os"
    "strconv"
)

func main() {
    writer := bufio.NewWriter(os.Stdout)
    var n,k int
    fmt.Scan(&n,&k)
    if (n/2 > k) || ((n < 2) && (k > 0)) {
        writer.WriteString("-1\n")
    } else if k == 0 {
        writer.WriteString("1\n")
    } else if (n/2) == k {
        for i := 1; i <= n; i++ {
            writer.WriteString(strconv.Itoa(i))
            if i == n { writer.WriteRune('\n') } else { writer.WriteRune(' ') }
        }
    } else {
        a := k-((n/2)-1)
        writer.WriteString(strconv.Itoa(a)+" "+strconv.Itoa(a*2))
        for i := 1; i <= (n-2); i++ {
            writer.WriteString(" "+strconv.Itoa(i+100000000))
        }
        writer.WriteRune('\n')
    }
    writer.Flush()
}