結果
| 問題 | No.2522 Fall in love, Girls! |
| コンテスト | |
| ユーザー |
hitonanode
|
| 提出日時 | 2023-10-27 22:21:02 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.89.0) |
| 結果 |
AC
|
| 実行時間 | 1,877 ms / 2,000 ms |
| コード長 | 31,086 bytes |
| 記録 | |
| コンパイル時間 | 3,035 ms |
| コンパイル使用メモリ | 219,324 KB |
| 実行使用メモリ | 26,004 KB |
| 最終ジャッジ日時 | 2024-09-25 14:23:28 |
| 合計ジャッジ時間 | 14,199 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 30 |
ソースコード
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <forward_list>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using lint = long long;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_;
#define ALL(x) (x).begin(), (x).end()
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)
#define REP(i, n) FOR(i,0,n)
#define IREP(i, n) IFOR(i,0,n)
template <typename T> bool chmax(T &m, const T q) { return m < q ? (m = q, true) : false; }
template <typename T> bool chmin(T &m, const T q) { return m > q ? (m = q, true) : false; }
const std::vector<std::pair<int, int>> grid_dxs{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int floor_lg(long long x) { return x <= 0 ? -1 : 63 - __builtin_clzll(x); }
template <class T1, class T2> T1 floor_div(T1 num, T2 den) { return (num > 0 ? num / den : -((-num + den - 1) / den)); }
template <class T1, class T2> std::pair<T1, T2> operator+(const std::pair<T1, T2> &l, const std::pair<T1, T2> &r) { return std::make_pair(l.first + r.first, l.second + r.second); }
template <class T1, class T2> std::pair<T1, T2> operator-(const std::pair<T1, T2> &l, const std::pair<T1, T2> &r) { return std::make_pair(l.first - r.first, l.second - r.second); }
template <class T> std::vector<T> sort_unique(std::vector<T> vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; }
template <class T> int arglb(const std::vector<T> &v, const T &x) { return std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), x)); }
template <class T> int argub(const std::vector<T> &v, const T &x) { return std::distance(v.begin(), std::upper_bound(v.begin(), v.end(), x)); }
template <class IStream, class T> IStream &operator>>(IStream &is, std::vector<T> &vec) { for (auto &v : vec) is >> v; return is; }
template <class OStream, class T> OStream &operator<<(OStream &os, const std::vector<T> &vec);
template <class OStream, class T, size_t sz> OStream &operator<<(OStream &os, const std::array<T, sz> &arr);
template <class OStream, class T, class TH> OStream &operator<<(OStream &os, const std::unordered_set<T, TH> &vec);
template <class OStream, class T, class U> OStream &operator<<(OStream &os, const pair<T, U> &pa);
template <class OStream, class T> OStream &operator<<(OStream &os, const std::deque<T> &vec);
template <class OStream, class T> OStream &operator<<(OStream &os, const std::set<T> &vec);
template <class OStream, class T> OStream &operator<<(OStream &os, const std::multiset<T> &vec);
template <class OStream, class T> OStream &operator<<(OStream &os, const std::unordered_multiset<T> &vec);
template <class OStream, class T, class U> OStream &operator<<(OStream &os, const std::pair<T, U> &pa);
template <class OStream, class TK, class TV> OStream &operator<<(OStream &os, const std::map<TK, TV> &mp);
template <class OStream, class TK, class TV, class TH> OStream &operator<<(OStream &os, const std::unordered_map<TK, TV, TH> &mp);
template <class OStream, class... T> OStream &operator<<(OStream &os, const std::tuple<T...> &tpl);
template <class OStream, class T> OStream &operator<<(OStream &os, const std::vector<T> &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <class OStream, class T, size_t sz> OStream &operator<<(OStream &os, const std::array<T, sz> &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; }
template <class... T> std::istream &operator>>(std::istream &is, std::tuple<T...> &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; }
template <class OStream, class... T> OStream &operator<<(OStream &os, const std::tuple<T...> &tpl) { os << '('; std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os << ')'; }
template <class OStream, class T, class TH> OStream &operator<<(OStream &os, const std::unordered_set<T, TH> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <class OStream, class T> OStream &operator<<(OStream &os, const std::deque<T> &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <class OStream, class T> OStream &operator<<(OStream &os, const std::set<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <class OStream, class T> OStream &operator<<(OStream &os, const std::multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <class OStream, class T> OStream &operator<<(OStream &os, const std::unordered_multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <class OStream, class T, class U> OStream &operator<<(OStream &os, const std::pair<T, U> &pa) { return os << '(' << pa.first << ',' << pa.second << ')'; }
template <class OStream, class TK, class TV> OStream &operator<<(OStream &os, const std::map<TK, TV> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
template <class OStream, class TK, class TV, class TH> OStream &operator<<(OStream &os, const std::unordered_map<TK, TV, TH> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
#ifdef HITONANODE_LOCAL
const string COLOR_RESET = "\033[0m", BRIGHT_GREEN = "\033[1;32m", BRIGHT_RED = "\033[1;31m", BRIGHT_CYAN = "\033[1;36m", NORMAL_CROSSED = "\033[0;9;37m", RED_BACKGROUND = "\033[1;41m", NORMAL_FAINT = "\033[0;2m";
#define dbg(x) std::cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << std::endl
#define dbgif(cond, x) ((cond) ? std::cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << std::endl : std::cerr)
#else
#define dbg(x) ((void)0)
#define dbgif(cond, x) ((void)0)
#endif
template <int md> struct ModInt {
using lint = long long;
constexpr static int mod() { return md; }
static int get_primitive_root() {
static int primitive_root = 0;
if (!primitive_root) {
primitive_root = [&]() {
std::set<int> fac;
int v = md - 1;
for (lint i = 2; i * i <= v; i++)
while (v % i == 0) fac.insert(i), v /= i;
if (v > 1) fac.insert(v);
for (int g = 1; g < md; g++) {
bool ok = true;
for (auto i : fac)
if (ModInt(g).pow((md - 1) / i) == 1) {
ok = false;
break;
}
if (ok) return g;
}
return -1;
}();
}
return primitive_root;
}
int val_;
int val() const noexcept { return val_; }
constexpr ModInt() : val_(0) {}
constexpr ModInt &_setval(lint v) { return val_ = (v >= md ? v - md : v), *this; }
constexpr ModInt(lint v) { _setval(v % md + md); }
constexpr explicit operator bool() const { return val_ != 0; }
constexpr ModInt operator+(const ModInt &x) const {
return ModInt()._setval((lint)val_ + x.val_);
}
constexpr ModInt operator-(const ModInt &x) const {
return ModInt()._setval((lint)val_ - x.val_ + md);
}
constexpr ModInt operator*(const ModInt &x) const {
return ModInt()._setval((lint)val_ * x.val_ % md);
}
constexpr ModInt operator/(const ModInt &x) const {
return ModInt()._setval((lint)val_ * x.inv().val() % md);
}
constexpr ModInt operator-() const { return ModInt()._setval(md - val_); }
constexpr ModInt &operator+=(const ModInt &x) { return *this = *this + x; }
constexpr ModInt &operator-=(const ModInt &x) { return *this = *this - x; }
constexpr ModInt &operator*=(const ModInt &x) { return *this = *this * x; }
constexpr ModInt &operator/=(const ModInt &x) { return *this = *this / x; }
friend constexpr ModInt operator+(lint a, const ModInt &x) {
return ModInt()._setval(a % md + x.val_);
}
friend constexpr ModInt operator-(lint a, const ModInt &x) {
return ModInt()._setval(a % md - x.val_ + md);
}
friend constexpr ModInt operator*(lint a, const ModInt &x) {
return ModInt()._setval(a % md * x.val_ % md);
}
friend constexpr ModInt operator/(lint a, const ModInt &x) {
return ModInt()._setval(a % md * x.inv().val() % md);
}
constexpr bool operator==(const ModInt &x) const { return val_ == x.val_; }
constexpr bool operator!=(const ModInt &x) const { return val_ != x.val_; }
constexpr bool operator<(const ModInt &x) const {
return val_ < x.val_;
} // To use std::map<ModInt, T>
friend std::istream &operator>>(std::istream &is, ModInt &x) {
lint t;
return is >> t, x = ModInt(t), is;
}
constexpr friend std::ostream &operator<<(std::ostream &os, const ModInt &x) {
return os << x.val_;
}
constexpr ModInt pow(lint n) const {
ModInt ans = 1, tmp = *this;
while (n) {
if (n & 1) ans *= tmp;
tmp *= tmp, n >>= 1;
}
return ans;
}
static constexpr int cache_limit = std::min(md, 1 << 21);
static std::vector<ModInt> facs, facinvs, invs;
constexpr static void _precalculation(int N) {
const int l0 = facs.size();
if (N > md) N = md;
if (N <= l0) return;
facs.resize(N), facinvs.resize(N), invs.resize(N);
for (int i = l0; i < N; i++) facs[i] = facs[i - 1] * i;
facinvs[N - 1] = facs.back().pow(md - 2);
for (int i = N - 2; i >= l0; i--) facinvs[i] = facinvs[i + 1] * (i + 1);
for (int i = N - 1; i >= l0; i--) invs[i] = facinvs[i] * facs[i - 1];
}
constexpr ModInt inv() const {
if (this->val_ < cache_limit) {
if (facs.empty()) facs = {1}, facinvs = {1}, invs = {0};
while (this->val_ >= int(facs.size())) _precalculation(facs.size() * 2);
return invs[this->val_];
} else {
return this->pow(md - 2);
}
}
constexpr ModInt fac() const {
while (this->val_ >= int(facs.size())) _precalculation(facs.size() * 2);
return facs[this->val_];
}
constexpr ModInt facinv() const {
while (this->val_ >= int(facs.size())) _precalculation(facs.size() * 2);
return facinvs[this->val_];
}
constexpr ModInt doublefac() const {
lint k = (this->val_ + 1) / 2;
return (this->val_ & 1) ? ModInt(k * 2).fac() / (ModInt(2).pow(k) * ModInt(k).fac())
: ModInt(k).fac() * ModInt(2).pow(k);
}
constexpr ModInt nCr(int r) const {
if (r < 0 or this->val_ < r) return ModInt(0);
return this->fac() * (*this - r).facinv() * ModInt(r).facinv();
}
constexpr ModInt nPr(int r) const {
if (r < 0 or this->val_ < r) return ModInt(0);
return this->fac() * (*this - r).facinv();
}
static ModInt binom(int n, int r) {
static long long bruteforce_times = 0;
if (r < 0 or n < r) return ModInt(0);
if (n <= bruteforce_times or n < (int)facs.size()) return ModInt(n).nCr(r);
r = std::min(r, n - r);
ModInt ret = ModInt(r).facinv();
for (int i = 0; i < r; ++i) ret *= n - i;
bruteforce_times += r;
return ret;
}
// Multinomial coefficient, (k_1 + k_2 + ... + k_m)! / (k_1! k_2! ... k_m!)
// Complexity: O(sum(ks))
template <class Vec> static ModInt multinomial(const Vec &ks) {
ModInt ret{1};
int sum = 0;
for (int k : ks) {
assert(k >= 0);
ret *= ModInt(k).facinv(), sum += k;
}
return ret * ModInt(sum).fac();
}
// Catalan number, C_n = binom(2n, n) / (n + 1)
// C_0 = 1, C_1 = 1, C_2 = 2, C_3 = 5, C_4 = 14, ...
// https://oeis.org/A000108
// Complexity: O(n)
static ModInt catalan(int n) {
if (n < 0) return ModInt(0);
return ModInt(n * 2).fac() * ModInt(n + 1).facinv() * ModInt(n).facinv();
}
ModInt sqrt() const {
if (val_ == 0) return 0;
if (md == 2) return val_;
if (pow((md - 1) / 2) != 1) return 0;
ModInt b = 1;
while (b.pow((md - 1) / 2) == 1) b += 1;
int e = 0, m = md - 1;
while (m % 2 == 0) m >>= 1, e++;
ModInt x = pow((m - 1) / 2), y = (*this) * x * x;
x *= (*this);
ModInt z = b.pow(m);
while (y != 1) {
int j = 0;
ModInt t = y;
while (t != 1) j++, t *= t;
z = z.pow(1LL << (e - j - 1));
x *= z, z *= z, y *= z;
e = j;
}
return ModInt(std::min(x.val_, md - x.val_));
}
};
template <int md> std::vector<ModInt<md>> ModInt<md>::facs = {1};
template <int md> std::vector<ModInt<md>> ModInt<md>::facinvs = {1};
template <int md> std::vector<ModInt<md>> ModInt<md>::invs = {0};
using mint = ModInt<998244353>;
// Directed graph library to find strongly connected components (強連結成分分解)
// 0-indexed directed graph
// Complexity: O(V + E)
struct DirectedGraphSCC {
int V; // # of Vertices
std::vector<std::vector<int>> to, from;
std::vector<int> used; // Only true/false
std::vector<int> vs;
std::vector<int> cmp;
int scc_num = -1;
DirectedGraphSCC(int V = 0) : V(V), to(V), from(V), cmp(V) {}
void _dfs(int v) {
used[v] = true;
for (auto t : to[v])
if (!used[t]) _dfs(t);
vs.push_back(v);
}
void _rdfs(int v, int k) {
used[v] = true;
cmp[v] = k;
for (auto t : from[v])
if (!used[t]) _rdfs(t, k);
}
void add_edge(int from_, int to_) {
assert(from_ >= 0 and from_ < V and to_ >= 0 and to_ < V);
to[from_].push_back(to_);
from[to_].push_back(from_);
}
// Detect strongly connected components and return # of them.
// Also, assign each vertex `v` the scc id `cmp[v]` (0-indexed)
int FindStronglyConnectedComponents() {
used.assign(V, false);
vs.clear();
for (int v = 0; v < V; v++)
if (!used[v]) _dfs(v);
used.assign(V, false);
scc_num = 0;
for (int i = (int)vs.size() - 1; i >= 0; i--)
if (!used[vs[i]]) _rdfs(vs[i], scc_num++);
return scc_num;
}
// Find and output the vertices that form a closed cycle.
// output: {v_1, ..., v_C}, where C is the length of cycle,
// {} if there's NO cycle (graph is DAG)
int _c, _init;
std::vector<int> _ret_cycle;
bool _dfs_detectcycle(int now, bool b0) {
if (now == _init and b0) return true;
for (auto nxt : to[now])
if (cmp[nxt] == _c and !used[nxt]) {
_ret_cycle.emplace_back(nxt), used[nxt] = 1;
if (_dfs_detectcycle(nxt, true)) return true;
_ret_cycle.pop_back();
}
return false;
}
std::vector<int> DetectCycle() {
int ns = FindStronglyConnectedComponents();
if (ns == V) return {};
std::vector<int> cnt(ns);
for (auto x : cmp) cnt[x]++;
_c = std::find_if(cnt.begin(), cnt.end(), [](int x) { return x > 1; }) - cnt.begin();
_init = std::find(cmp.begin(), cmp.end(), _c) - cmp.begin();
used.assign(V, false);
_ret_cycle.clear();
_dfs_detectcycle(_init, false);
return _ret_cycle;
}
// After calling `FindStronglyConnectedComponents()`, generate a new graph by uniting all
// vertices belonging to the same component(The resultant graph is DAG).
DirectedGraphSCC GenerateTopologicalGraph() {
DirectedGraphSCC newgraph(scc_num);
for (int s = 0; s < V; s++)
for (auto t : to[s]) {
if (cmp[s] != cmp[t]) newgraph.add_edge(cmp[s], cmp[t]);
}
return newgraph;
}
};
// 2-SAT solver: Find a solution for `(Ai v Aj) ^ (Ak v Al) ^ ... = true`
// - `nb_sat_vars`: Number of variables
// - Considering a graph with `2 * nb_sat_vars` vertices
// - Vertices [0, nb_sat_vars) means `Ai`
// - vertices [nb_sat_vars, 2 * nb_sat_vars) means `not Ai`
struct SATSolver : DirectedGraphSCC {
int nb_sat_vars;
std::vector<int> solution;
SATSolver(int nb_variables = 0)
: DirectedGraphSCC(nb_variables * 2), nb_sat_vars(nb_variables), solution(nb_sat_vars) {}
void add_x_or_y_constraint(bool is_x_true, int x, bool is_y_true, int y) {
assert(x >= 0 and x < nb_sat_vars);
assert(y >= 0 and y < nb_sat_vars);
if (!is_x_true) x += nb_sat_vars;
if (!is_y_true) y += nb_sat_vars;
add_edge((x + nb_sat_vars) % (nb_sat_vars * 2), y);
add_edge((y + nb_sat_vars) % (nb_sat_vars * 2), x);
}
// Solve the 2-SAT problem. If no solution exists, return `false`.
// Otherwise, dump one solution to `solution` and return `true`.
bool run() {
FindStronglyConnectedComponents();
for (int i = 0; i < nb_sat_vars; i++) {
if (cmp[i] == cmp[i + nb_sat_vars]) return false;
solution[i] = cmp[i] > cmp[i + nb_sat_vars];
}
return true;
}
};
#include <algorithm>
#include <cassert>
#include <deque>
#include <fstream>
#include <functional>
#include <limits>
#include <queue>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
template <typename T, T INF = std::numeric_limits<T>::max() / 2, int INVALID = -1>
struct shortest_path {
int V, E;
bool single_positive_weight;
T wmin, wmax;
std::vector<std::pair<int, T>> tos;
std::vector<int> head;
std::vector<std::tuple<int, int, T>> edges;
void build_() {
if (int(tos.size()) == E and int(head.size()) == V + 1) return;
tos.resize(E);
head.assign(V + 1, 0);
for (const auto &e : edges) ++head[std::get<0>(e) + 1];
for (int i = 0; i < V; ++i) head[i + 1] += head[i];
auto cur = head;
for (const auto &e : edges) {
tos[cur[std::get<0>(e)]++] = std::make_pair(std::get<1>(e), std::get<2>(e));
}
}
shortest_path(int V = 0) : V(V), E(0), single_positive_weight(true), wmin(0), wmax(0) {}
void add_edge(int s, int t, T w) {
assert(0 <= s and s < V);
assert(0 <= t and t < V);
edges.emplace_back(s, t, w);
++E;
if (w > 0 and wmax > 0 and wmax != w) single_positive_weight = false;
wmin = std::min(wmin, w);
wmax = std::max(wmax, w);
}
void add_bi_edge(int u, int v, T w) {
add_edge(u, v, w);
add_edge(v, u, w);
}
std::vector<T> dist;
std::vector<int> prev;
// Dijkstra algorithm
// - Requirement: wmin >= 0
// - Complexity: O(E log E)
using Pque = std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>,
std::greater<std::pair<T, int>>>;
template <class Heap = Pque> void dijkstra(int s, int t = INVALID) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF);
prev.assign(V, INVALID);
dist[s] = 0;
Heap pq;
pq.emplace(0, s);
while (!pq.empty()) {
T d;
int v;
std::tie(d, v) = pq.top();
pq.pop();
if (t == v) return;
if (dist[v] < d) continue;
for (int e = head[v]; e < head[v + 1]; ++e) {
const auto &nx = tos[e];
T dnx = d + nx.second;
if (dist[nx.first] > dnx) {
dist[nx.first] = dnx, prev[nx.first] = v;
pq.emplace(dnx, nx.first);
}
}
}
}
// Dijkstra algorithm
// - Requirement: wmin >= 0
// - Complexity: O(V^2 + E)
void dijkstra_vquad(int s, int t = INVALID) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF);
prev.assign(V, INVALID);
dist[s] = 0;
std::vector<char> fixed(V, false);
while (true) {
int r = INVALID;
T dr = INF;
for (int i = 0; i < V; i++) {
if (!fixed[i] and dist[i] < dr) r = i, dr = dist[i];
}
if (r == INVALID or r == t) break;
fixed[r] = true;
int nxt;
T dx;
for (int e = head[r]; e < head[r + 1]; ++e) {
std::tie(nxt, dx) = tos[e];
if (dist[nxt] > dist[r] + dx) dist[nxt] = dist[r] + dx, prev[nxt] = r;
}
}
}
// Bellman-Ford algorithm
// - Requirement: no negative loop
// - Complexity: O(VE)
bool bellman_ford(int s, int nb_loop) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF), prev.assign(V, INVALID);
dist[s] = 0;
for (int l = 0; l < nb_loop; l++) {
bool upd = false;
for (int v = 0; v < V; v++) {
if (dist[v] == INF) continue;
for (int e = head[v]; e < head[v + 1]; ++e) {
const auto &nx = tos[e];
T dnx = dist[v] + nx.second;
if (dist[nx.first] > dnx) dist[nx.first] = dnx, prev[nx.first] = v, upd = true;
}
}
if (!upd) return true;
}
return false;
}
// Bellman-ford algorithm using deque
// - Requirement: no negative loop
// - Complexity: O(VE)
void spfa(int s) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF);
prev.assign(V, INVALID);
dist[s] = 0;
std::deque<int> q;
std::vector<char> in_queue(V);
q.push_back(s), in_queue[s] = 1;
while (!q.empty()) {
int now = q.front();
q.pop_front(), in_queue[now] = 0;
for (int e = head[now]; e < head[now + 1]; ++e) {
const auto &nx = tos[e];
T dnx = dist[now] + nx.second;
int nxt = nx.first;
if (dist[nxt] > dnx) {
dist[nxt] = dnx;
if (!in_queue[nxt]) {
if (q.size() and dnx < dist[q.front()]) { // Small label first optimization
q.push_front(nxt);
} else {
q.push_back(nxt);
}
prev[nxt] = now, in_queue[nxt] = 1;
}
}
}
}
}
// 01-BFS
// - Requirement: all weights must be 0 or w (positive constant).
// - Complexity: O(V + E)
void zero_one_bfs(int s, int t = INVALID) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF), prev.assign(V, INVALID);
dist[s] = 0;
std::vector<int> q(V * 4);
int ql = V * 2, qr = V * 2;
q[qr++] = s;
while (ql < qr) {
int v = q[ql++];
if (v == t) return;
for (int e = head[v]; e < head[v + 1]; ++e) {
const auto &nx = tos[e];
T dnx = dist[v] + nx.second;
if (dist[nx.first] > dnx) {
dist[nx.first] = dnx, prev[nx.first] = v;
if (nx.second) {
q[qr++] = nx.first;
} else {
q[--ql] = nx.first;
}
}
}
}
}
// Dial's algorithm
// - Requirement: wmin >= 0
// - Complexity: O(wmax * V + E)
void dial(int s, int t = INVALID) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF), prev.assign(V, INVALID);
dist[s] = 0;
std::vector<std::vector<std::pair<int, T>>> q(wmax + 1);
q[0].emplace_back(s, dist[s]);
int ninq = 1;
int cur = 0;
T dcur = 0;
for (; ninq; ++cur, ++dcur) {
if (cur == wmax + 1) cur = 0;
while (!q[cur].empty()) {
int v = q[cur].back().first;
T dnow = q[cur].back().second;
q[cur].pop_back(), --ninq;
if (v == t) return;
if (dist[v] < dnow) continue;
for (int e = head[v]; e < head[v + 1]; ++e) {
const auto &nx = tos[e];
T dnx = dist[v] + nx.second;
if (dist[nx.first] > dnx) {
dist[nx.first] = dnx, prev[nx.first] = v;
int nxtcur = cur + int(nx.second);
if (nxtcur >= int(q.size())) nxtcur -= q.size();
q[nxtcur].emplace_back(nx.first, dnx), ++ninq;
}
}
}
}
}
// Solver for DAG
// - Requirement: graph is DAG
// - Complexity: O(V + E)
bool dag_solver(int s) {
assert(0 <= s and s < V);
build_();
dist.assign(V, INF), prev.assign(V, INVALID);
dist[s] = 0;
std::vector<int> indeg(V, 0);
std::vector<int> q(V * 2);
int ql = 0, qr = 0;
q[qr++] = s;
while (ql < qr) {
int now = q[ql++];
for (int e = head[now]; e < head[now + 1]; ++e) {
const auto &nx = tos[e];
++indeg[nx.first];
if (indeg[nx.first] == 1) q[qr++] = nx.first;
}
}
ql = qr = 0;
q[qr++] = s;
while (ql < qr) {
int now = q[ql++];
for (int e = head[now]; e < head[now + 1]; ++e) {
const auto &nx = tos[e];
--indeg[nx.first];
if (dist[nx.first] > dist[now] + nx.second)
dist[nx.first] = dist[now] + nx.second, prev[nx.first] = now;
if (indeg[nx.first] == 0) q[qr++] = nx.first;
}
}
return *max_element(indeg.begin(), indeg.end()) == 0;
}
// Retrieve a sequence of vertex ids that represents shortest path [s, ..., goal]
// If not reachable to goal, return {}
std::vector<int> retrieve_path(int goal) const {
assert(int(prev.size()) == V);
assert(0 <= goal and goal < V);
if (dist[goal] == INF) return {};
std::vector<int> ret{goal};
while (prev[goal] != INVALID) {
goal = prev[goal];
ret.push_back(goal);
}
std::reverse(ret.begin(), ret.end());
return ret;
}
void solve(int s, int t = INVALID) {
if (wmin >= 0) {
if (single_positive_weight) {
zero_one_bfs(s, t);
} else if (wmax <= 10) {
dial(s, t);
} else {
if ((long long)V * V < (E << 4)) {
dijkstra_vquad(s, t);
} else {
dijkstra(s, t);
}
}
} else {
bellman_ford(s, V);
}
}
// Warshall-Floyd algorithm
// - Requirement: no negative loop
// - Complexity: O(E + V^3)
std::vector<std::vector<T>> floyd_warshall() {
build_();
std::vector<std::vector<T>> dist2d(V, std::vector<T>(V, INF));
for (int i = 0; i < V; i++) {
dist2d[i][i] = 0;
for (const auto &e : edges) {
int s = std::get<0>(e), t = std::get<1>(e);
dist2d[s][t] = std::min(dist2d[s][t], std::get<2>(e));
}
}
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
if (dist2d[i][k] == INF) continue;
for (int j = 0; j < V; j++) {
if (dist2d[k][j] == INF) continue;
dist2d[i][j] = std::min(dist2d[i][j], dist2d[i][k] + dist2d[k][j]);
}
}
}
return dist2d;
}
void to_dot(std::string filename = "shortest_path") const {
std::ofstream ss(filename + ".DOT");
ss << "digraph{\n";
build_();
for (int i = 0; i < V; i++) {
for (int e = head[i]; e < head[i + 1]; ++e) {
ss << i << "->" << tos[e].first << "[label=" << tos[e].second << "];\n";
}
}
ss << "}\n";
ss.close();
return;
}
};
int main() {
int N, M, K;
cin >> N >> M >> K;
vector<pint> xys(K);
vector<int> zs;
for (auto &[x, y] : xys) {
cin >> x >> y;
--x, --y;
zs.push_back(x);
zs.push_back(y);
}
zs = sort_unique(zs);
const int D = zs.size();
int free_sub = M, free_notsub = N - M;
for (int d : zs) {
if (d < M) --free_sub;
else --free_notsub;
}
vector<pint> ixys;
for (auto [x, y] : xys) ixys.emplace_back(arglb(zs, x), arglb(zs, y));
dbg(ixys);
DirectedGraphSCC scc(D);
shortest_path<int> sp(D);
for (auto [x, y] : ixys) scc.add_edge(x, y), sp.add_edge(x, y, 0);
if (scc.FindStronglyConnectedComponents() < D) {
puts("0");
return 0;
}
if (K == 0) {
cout << mint(N - M) * mint(N - 1).fac() << '\n';
return 0;
}
const auto dmat = sp.floyd_warshall();
vector<int> is_ok(1 << D, true);
REP(S, 1 << D) {
REP(i, D) REP(j, D) {
if (dmat.at(i).at(j) == 0 and ((S >> j) & 1) and ((S >> i) & 1) == 0) is_ok.at(S) = false;
}
}
vector<mint> dp(1 << D);
if (is_ok.back()) dp.back() = 1;
IREP(S, 1 << D) {
if (!is_ok.at(S)) continue;
REP(i, D) {
if ((S >> i) & 1) {
const int Snxt = S - (1 << i);
if (!is_ok.at(Snxt)) continue;
dp.at(Snxt) += dp.at(S);
}
}
}
mint ret = 0;
dbg(N);
REP(d, D) {
const mint v = dp.at(1 << d);
dbg(make_tuple(d, v, zs.at(d) < M, free_sub, free_notsub));
if (free_notsub) {
ret += mint(free_notsub) * mint(free_sub + free_notsub - 1).fac() * mint(N - 1).nCr(D) * v;
}
if (zs.at(d) >= M) {
// dbg(make_tuple(N, D, v));
ret += mint(N - 1).nCr(D - 1) * v * mint(free_sub + free_notsub).fac();
}
}
cout << ret << '\n';
}
hitonanode