canuc80k3211·12/50

Những Tuyến Đường Qua Cổng Dịch Chuyển

Nộp bài trên LQDOJ

Bài 32 · Topological Sort

Một trò chơi có cửa ải, được đánh số từ đến , cùng cổng dịch chuyển một chiều. Mỗi cổng cho phép đi từ một cửa ải đến một cửa ải .

Hệ thống được thiết kế sao cho không có chu trình có hướng: sau khi đi qua ít nhất một cổng, người chơi không thể quay lại cửa ải đã từng đứng trước đó.

Người chơi bắt đầu ở cửa ải và hoàn thành trò chơi khi tới cửa ải . Một cách hoàn thành là một dãy các cổng được sử dụng liên tiếp, đúng theo chiều của từng cổng. Hai cách được xem là khác nhau nếu tại một bước nào đó chúng sử dụng hai cổng khác nhau. Vì vậy, nếu input chứa nhiều cổng cùng nối từ đến , mỗi cổng vẫn là một lựa chọn riêng.

Hãy đếm số cách hoàn thành trò chơi. Vì kết quả có thể rất lớn, chỉ cần in phần dư khi chia cho .

Input

  • Dòng đầu chứa hai số nguyên và .
  • dòng tiếp theo, mỗi dòng chứa hai số nguyên và , mô tả một cổng dịch chuyển một chiều từ đến .

Output

  • In một số nguyên: số cách đi từ cửa ải đến cửa ải , lấy modulo .

Constraints

  • .
  • .
  • .
  • Đồ thị tạo bởi các cổng dịch chuyển không chứa chu trình có hướng.

Scoring

  • Subtask ( số điểm): và .
  • Subtask ( số điểm): Không có giới hạn bổ sung.

Example

Test 1

Input

5 6
1 2
1 3
2 4
3 4
4 5
2 5

Output

3

Giải thích: Ba cách là và .

Test 2

Input

6 5
1 2
2 3
4 5
5 6
4 6

Output

0

Giải thích: Từ cửa ải chỉ có thể đi tới rồi ; không có cổng nào đưa người chơi từ phần này tới cửa ải , nên không có cách hoàn thành.

Lời giải tóm tắt
  • Ý tưởng: Đặt ways[v] là số cách đi từ cửa ải 1 tới cửa ải v, lấy modulo 1 000 000 007. Khởi tạo ways[1] = 1; các giá trị khác bằng 0.
  • Ý tưởng: Ta xử lý các cửa ải theo thứ tự topo bằng thuật toán Kahn. Khi lấy một cửa ải u ra khỏi hàng đợi, mọi cổng đi vào u đã được xét. Với mỗi cổng u → v, mọi cách tới u có thể nối thêm cổng này để tạo một cách tới v, nên cập nhật
  • Ý tưởng:

text ways[v] = (ways[v] + ways[u]) mod 1 000 000 007. - Ý tưởng: Nếu có nhiều cổng cùng nối u tới v, vòng lặp xử lý từng cổng một, đúng với việc mỗi cổng là một lựa chọn riêng. - Tính đúng đắn: Bổ đề 1. Khi đỉnh u được lấy ra theo thứ tự topo, ways[u] bằng số cách đi từ 1 tới u. - Tính đúng đắn: Chứng minh. Mọi cách không rỗng tới u có đúng một cổng cuối cùng x → u. Do x đứng trước u trong thứ tự topo, số cách tới x đã đúng và đã được cộng vào ways[u]. Các nhóm được phân biệt bởi cổng cuối cùng, nên phép cộng không bỏ sót và không đếm trùng. Riêng tại đỉnh 1, giá trị khởi tạo 1 biểu diễn trạng thái bắt đầu. ∎ - Tính đúng đắn: Bổ đề 2. Mỗi lần xử lý cổng u → v, thuật toán cộng chính xác số cách có cổng cuối cùng là cổng đó. - Tính đúng đắn: Chứng minh. Ghép cổng u → v vào từng cách tới u tạo ra đúng ways[u] cách tới v, và mọi cách sử dụng cổng này được tạo như vậy. ∎ - Tính đúng đắn: Định lý. Thuật toán in đúng số cách hoàn thành trò chơi modulo 1 000 000 007. - Tính đúng đắn: Chứng minh. Theo Bổ đề 1, sau khi xử lý topo, ways[n] là số cách từ 1 tới n. Mọi phép cộng đều được lấy modulo, nên giá trị in ra đúng theo yêu cầu. ∎ - Độ phức tạp: Mỗi cửa ải và mỗi cổng được xử lý hằng số lần. Thời gian là O(n + m), bộ nhớ là O(n + m).