// [TEMPLATE_BEGIN] #include #include #include #include #include // ==================== 単一値・基本入力 ==================== /** * @brief 標準入出力の高速化を行う。main関数の最初で呼ぶことを推奨。 */ inline void fast_io() { std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); } /** * @brief 任意の数の変数を標準入力から読み込む * @tparam Ts 引数の型パック * @param args 読み込み先の変数 */ template inline void scan(Ts&... args) { (std::cin >> ... >> args); } /** * @brief 単一の値を標準入力から読み込む * @tparam T 読み込む値の型 (デフォルト: int) * @return 読み込んだ値 */ template inline T read() { T x; std::cin >> x; return x; } // ==================== ベクター入力 ==================== /** * @brief 1次元ベクターを標準入力から読み込む(算術型用、offset 付き) * @tparam T 要素の型 (デフォルト: int) * @param n 要素数 * @param offset 読み込み時に引く値 (デフォルト: 0) * @return 読み込んだベクター */ template requires std::is_arithmetic_v inline std::vector read_vec(int n, T offset = 0) { std::vector v(n); for (auto& x : v) { std::cin >> x; x -= offset; } return v; } /** * @brief 1次元ベクターを標準入力から読み込む(非算術型用) * @tparam T 要素の型 * @param n 要素数 * @return 読み込んだベクター */ template requires(!std::is_arithmetic_v) inline std::vector read_vec(int n) { std::vector v(n); for (auto& x : v) { std::cin >> x; } return v; } /** * @brief 2次元ベクターを標準入力から読み込む(算術型用、offset 付き) * @tparam T 要素の型 (デフォルト: int) * @param h 行数 * @param w 列数 * @param offset 読み込み時に引く値 (デフォルト: 0) * @return 読み込んだ h×w の2次元ベクター */ template requires std::is_arithmetic_v inline std::vector> read_vec2(int h, int w, T offset = 0) { std::vector> v(h, std::vector(w)); for (auto& row : v) { for (auto& x : row) { std::cin >> x; x -= offset; } } return v; } /** * @brief 2次元ベクターを標準入力から読み込む(非算術型用) * @tparam T 要素の型 * @param h 行数 * @param w 列数 * @return 読み込んだ h×w の2次元ベクター */ template requires(!std::is_arithmetic_v) inline std::vector> read_vec2(int h, int w) { std::vector> v(h, std::vector(w)); for (auto& row : v) { for (auto& x : row) { std::cin >> x; } } return v; } /** * @brief 各行の最初に要素数が与えられる可変長2次元ベクターを標準入力から読み込む(算術型用、offset 付き) * @tparam T 要素の型 (デフォルト: int) * @param h 行数 * @param offset 読み込み時に引く値 (デフォルト: 0) * @return 読み込んだ可変長の2次元ベクター */ template requires std::is_arithmetic_v inline std::vector> read_vec2_var(int h, T offset = 0) { std::vector> v(h); for (auto& row : v) { int m; std::cin >> m; row = read_vec(m, offset); } return v; } /** * @brief 各行の最初に要素数が与えられる可変長2次元ベクターを標準入力から読み込む(非算術型用) * @tparam T 要素の型 * @param h 行数 * @return 読み込んだ可変長の2次元ベクター */ template requires(!std::is_arithmetic_v) inline std::vector> read_vec2_var(int h) { std::vector> v(h); for (auto& row : v) { int m; std::cin >> m; row = read_vec(m); } return v; } /** * @brief 1次元のペアのベクターを標準入力から読み込む * @tparam T1 ペアの1つ目の要素の型 (デフォルト: int) * @tparam T2 ペアの2つ目の要素の型 (デフォルト: int) * @param n 要素数 * @param offset1 1つ目の要素から引く値 (デフォルト: 0) * @param offset2 2つ目の要素から引く値 (デフォルト: 0) * @return 読み込んだペアのベクター */ template inline std::vector> read_vec_pair(int n, T1 offset1 = 0, T2 offset2 = 0) { std::vector> v(n); for (auto& [x, y] : v) { std::cin >> x >> y; x -= offset1; y -= offset2; } return v; } // ==================== 行列・三角形入力 ==================== /** * @brief 上三角行列形式の入力を読み込み、2次元ベクターとして返す(算術型用、offset 付き) * @tparam T 要素の型 (デフォルト: int) * @param n 行列のサイズ (n x n) * @param symmetric 対称行列にするかどうか (デフォルト: true) * @param offset 読み込み時に値から引く量 (デフォルト: 0) * @return 読み込んだ 2次元ベクター */ template requires std::is_arithmetic_v inline std::vector> read_upper_tri(int n, bool symmetric = true, T offset = 0) { std::vector> v(n, std::vector(n)); for (int i = 0; i < n - 1; ++i) { for (int j = i + 1; j < n; ++j) { std::cin >> v[i][j]; v[i][j] -= offset; if (symmetric) v[j][i] = v[i][j]; } } return v; } /** * @brief 上三角行列形式の入力を読み込み、2次元ベクターとして返す(非算術型用) * @tparam T 要素の型 * @param n 行列のサイズ (n x n) * @param symmetric 対称行列にするかどうか (デフォルト: true) * @return 読み込んだ 2次元ベクター */ template requires(!std::is_arithmetic_v) inline std::vector> read_upper_tri(int n, bool symmetric = true) { std::vector> v(n, std::vector(n)); for (int i = 0; i < n - 1; ++i) { for (int j = i + 1; j < n; ++j) { std::cin >> v[i][j]; if (symmetric) v[j][i] = v[i][j]; } } return v; } /** * @brief 下三角行列形式の入力を読み込み、2次元ベクターとして返す(算術型用、offset 付き) * @tparam T 要素の型 (デフォルト: int) * @param n 行列のサイズ (n x n) * @param symmetric 対称行列にするかどうか (デフォルト: true) * @param offset 読み込み時に値から引く量 (デフォルト: 0) * @return 読み込んだ 2次元ベクター */ template requires std::is_arithmetic_v inline std::vector> read_lower_tri(int n, bool symmetric = true, T offset = 0) { std::vector> v(n, std::vector(n)); for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) { std::cin >> v[i][j]; v[i][j] -= offset; if (symmetric) v[j][i] = v[i][j]; } } return v; } /** * @brief 下三角行列形式の入力を読み込み、2次元ベクターとして返す(非算術型用) * @tparam T 要素の型 * @param n 行列のサイズ (n x n) * @param symmetric 对称行列にするかどうか (デフォルト: true) * @return 読み込んだ 2次元ベクター */ template requires(!std::is_arithmetic_v) inline std::vector> read_lower_tri(int n, bool symmetric = true) { std::vector> v(n, std::vector(n)); for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) { std::cin >> v[i][j]; if (symmetric) v[j][i] = v[i][j]; } } return v; } // ==================== タプル入力 ==================== namespace detail { /** * @brief タプルの各要素を順番に読み込む(内部実装) * @tparam Tuple タプル型 * @tparam Is インデックスのパック * @param t 読み込み先のタプル */ template inline void read_tuple_impl(Tuple& t, std::index_sequence) { (std::cin >> ... >> std::get(t)); } } // namespace detail /** * @brief 複数の型の値をまとめてタプルとして読み込む * @tparam Ts 読み込む型のパック * @return 読み込んだ値を格納した std::tuple * * 使い方: * auto [a, b, c] = read_tuple(); */ template inline std::tuple read_tuple() { std::tuple t; detail::read_tuple_impl(t, std::index_sequence_for{}); return t; } /** * @brief n 行分のタプルをベクターとして読み込む * @tparam Ts 各行の型のパック * @param n 行数 * @return 読み込んだ std::tuple の std::vector * * 使い方: * auto v = read_vec_tuple(n); * auto [a, b, c] = v[i]; */ template inline std::vector> read_vec_tuple(int n) { std::vector> v(n); for (auto& t : v) detail::read_tuple_impl(t, std::index_sequence_for{}); return v; } // ==================== グラフ入力 ==================== /** * @brief 無向グラフを辺リストから隣接リスト形式で読み込む * @param n 頂点数 * @param m 辺数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の隣接リスト (vector>) * * 使い方: * auto g = read_graph(n, m, 1); // 1-indexed 入力 */ inline std::vector> read_graph(int n, int m, int base = 1) { std::vector> g(n); for (int i = 0; i < m; i++) { int u, v; std::cin >> u >> v; u -= base; v -= base; g[u].push_back(v); g[v].push_back(u); } return g; } /** * @brief 有向グラフを辺リストから隣接リスト形式で読み込む * @param n 頂点数 * @param m 辺数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の隣接リスト (vector>) * * 使い方: * auto g = read_digraph(n, m, 1); // 1-indexed 入力、u -> v の有向辺 */ inline std::vector> read_digraph(int n, int m, int base = 1) { std::vector> g(n); for (int i = 0; i < m; i++) { int u, v; std::cin >> u >> v; u -= base; v -= base; g[u].push_back(v); } return g; } /** * @brief 木を辺リストから隣接リスト形式で読み込む (n-1 辺) * @param n 頂点数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の隣接リスト (vector>) * * 使い方: * auto g = read_tree(n, 1); // 1-indexed 入力 */ inline std::vector> read_tree(int n, int base = 1) { return read_graph(n, n - 1, base); } /** * @brief 重み付き木を辺リストから隣接リスト形式で読み込む (n-1 辺) * @tparam W 辺の重みの型 * @param n 頂点数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の隣接リスト。各エントリは {隣接頂点, 重み} のペア * * 使い方: * auto g = read_weighted_tree(n, 1); */ template inline std::vector>> read_weighted_tree(int n, int base = 1) { return read_weighted_graph(n, n - 1, base); } /** * @brief 重み付き無向グラフを辺リストから隣接リスト形式で読み込む * @tparam W 辺の重みの型 * @param n 頂点数 * @param m 辺数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の隣接リスト。各エントリは {隣接頂点, 重み} のペア * * 使い方: * auto g = read_weighted_graph(n, m, 1); * for (auto [v, w] : g[u]) { ... } */ template inline std::vector>> read_weighted_graph(int n, int m, int base = 1) { std::vector>> g(n); for (int i = 0; i < m; i++) { int u, v; W w; std::cin >> u >> v >> w; u -= base; v -= base; g[u].emplace_back(v, w); g[v].emplace_back(u, w); } return g; } /** * @brief 重み付き有向グラフを辺リストから隣接リスト形式で読み込む * @tparam W 辺の重みの型 * @param n 頂点数 * @param m 辺数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の隣接リスト。各エントリは {隣接頂点, 重み} のペア * * 使い方: * auto g = read_weighted_digraph(n, m, 1); * for (auto [v, w] : g[u]) { ... } */ template inline std::vector>> read_weighted_digraph(int n, int m, int base = 1) { std::vector>> g(n); for (int i = 0; i < m; i++) { int u, v; W w; std::cin >> u >> v >> w; u -= base; v -= base; g[u].emplace_back(v, w); } return g; } // ==================== 辺リスト入力 ==================== /** * @brief 無向/有向グラフの辺リストを読み込む * @param m 辺数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の辺リスト (std::vector>) */ inline std::vector> read_edges(int m, int base = 1) { std::vector> edges(m); for (int i = 0; i < m; ++i) { int u, v; std::cin >> u >> v; edges[i] = {u - base, v - base}; } return edges; } /** * @brief 重み付き無向/有向グラフの辺リストを読み込む * @tparam W 辺の重みの型 * @param m 辺数 * @param base 入力の頂点番号のベース (0-indexed なら 0、1-indexed なら 1) * @return 0-indexed の重み付き辺リスト (std::vector>) */ template inline std::vector> read_weighted_edges(int m, int base = 1) { std::vector> edges(m); for (int i = 0; i < m; ++i) { int u, v; W w; std::cin >> u >> v >> w; edges[i] = {u - base, v - base, w}; } return edges; } #include #include #include #include #include #include /** * @brief aをaとbの最小値で更新 * @param a 更新対象 * @param b 比較値 * @return 更新されたらtrue */ template inline bool chmin(T& a, const U& b) { if (a > b) { a = b; return true; } return false; } /** * @brief aをaとbの最大値で更新 * @param a 更新対象 * @param b 比較値 * @return 更新されたらtrue */ template inline bool chmax(T& a, const U& b) { if (a < b) { a = b; return true; } return false; } /** * @brief 整数除算の切り上げ (b>0) * @param a 分子 * @param b 分母 * @return 切り上げ値 */ template inline T div_ceil(T a, T b) { if (a >= 0) return (a + b - 1) / b; return a / b; } /** * @brief 整数除算の切り捨て (b>0) * @param a 分子 * @param b 分母 * @return 切り捨て値 */ template inline T div_floor(T a, T b) { if (a >= 0) return a / b; return (a - b + 1) / b; } /** * @brief 連続整数のvector生成 * @param n 要素数 * @param start 開始値(デフォルト0) * @return 生成されたvector */ template inline std::vector iota_vec(int n, T start = 0) { std::vector v(n); std::iota(v.begin(), v.end(), start); return v; } namespace internal { /** * @brief 多次元のstd::vectorをデフォルト値で生成するヘルパー */ template inline auto make_vec_default(int n, Args... args) { if constexpr (sizeof...(args) == 0) { return std::vector(n); } else { return std::vector(n, make_vec_default(args...)); } } } // namespace internal /** * @brief 多次元のstd::vectorを初期値付きで生成する * @param n サイズ * @param init 初期値 * @return 1次元のstd::vector */ template inline std::vector make_vec(int n, const T& init) { return std::vector(n, init); } /** * @brief 多次元のstd::vectorを初期値付きで生成する(再帰・推論) * @param n 最初の次元のサイズ * @param args 残りの次元のサイズ、および最終的な初期値 * @return 多次元のstd::vector */ template inline auto make_vec(int n, Args... args) { return std::vector(n, make_vec(args...)); } /** * @brief 多次元のstd::vectorをデフォルト値で生成する * @tparam T 要素の型 * @param args 次元のサイズ列 * @return 多次元のstd::vector */ template inline auto make_vec(Args... args) { return internal::make_vec_default(args...); } /** * @brief 同じサイズの複数の多次元のstd::vectorを生成する * @tparam Ts 各vectorの要素型 * @param args 次元のサイズ列 * @return 生成された各テーブルを格納したstd::tuple */ template inline auto make_vecs(Args... args) { return std::make_tuple(internal::make_vec_default(args...)...); } /** * @brief vectorを2回反復連結 * @param v 元のvector * @return 2倍長のvector */ template inline std::vector doubled(const std::vector& v) { std::vector res; res.reserve(v.size() * 2); res.insert(res.end(), v.begin(), v.end()); res.insert(res.end(), v.begin(), v.end()); return res; } /** * @brief 区間[l1,r1)と[l2,r2)の共通長 * @param l1 区間1左端 * @param r1 区間1右端 * @param l2 区間2左端 * @param r2 区間2右端 * @return 共通部分の長さ(ない場合は0) */ template inline T overlap_length(T l1, T r1, T l2, T r2) { return std::max(static_cast(0), std::min(r1, r2) - std::max(l1, l2)); } /** * @brief "Yes"/"No"を出力 * @param b trueでYes, falseでNo */ inline void Yes(bool b = true) { std::println("{}", (b ? "Yes" : "No")); } /** * @brief "No"を出力 */ inline void No() { std::println("No"); } #ifdef LOCAL #include #else #define debug(...) #endif using namespace std; namespace rv = std::views; // NOLINT using lint = long long; #define ALL(a) (a).begin(), (a).end() // [TEMPLATE_END] void solve() { // Write your code here int N, M; scan(N, M); auto A = read_vec(M); auto check = [](int a, int b) { return b - a == 1; }; auto view = A | rv::chunk_by(check); vector> ans; for (auto rng : view) { ans.push_back({rng[0], ssize(rng)}); } println("{}", ssize(ans)); for (auto [a, b] : ans) { println("{} {}", a, b); } } int main() { fast_io(); solve(); }