#include using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int L, R; cin >> L >> R; // Build ADFA recognizing binary representations of [L,R] // Then minimize by merging nodes with identical subtrees (right languages) struct Edge { int to, w; }; // Phase 1: Build all nodes vector> adj; int n = 0; auto nn = [&]() -> int { adj.emplace_back(); return n++; }; int END = nn(); // 0 int START = nn(); // 1 // Free chain: free[k] accepts any k-bit suffix map fc; fc[0] = END; function getF = [&](int k) -> int { if (fc.count(k)) return fc[k]; int ch = getF(k-1), u = nn(); adj[u].push_back({ch, 0}); adj[u].push_back({ch, 1}); return fc[k] = u; }; // Range nodes: gr(k, lo, hi) accepts k-bit suffixes in [lo, hi] map,int> rc; function gr = [&](int k, int lo, int hi) -> int { if (lo > hi) return -1; if (k == 0) return (lo == 0 && hi == 0) ? END : -1; if (lo == 0 && hi == (1<second; int mid = 1 << (k-1); int left = -1, right = -1; if (lo <= min(hi, mid-1)) left = gr(k-1, lo, min(hi, mid-1)); if (max(lo, mid) <= hi) right = gr(k-1, max(lo, mid) - mid, hi - mid); if (left == -1 && right == -1) return rc[key] = -1; int u = nn(); if (left != -1) adj[u].push_back({left, 0}); if (right != -1) adj[u].push_back({right, 1}); return rc[key] = u; }; int lenL = 32 - __builtin_clz(L), lenR = 32 - __builtin_clz(R); for (int len = lenL; len <= lenR; len++) { int rs = 1 << (len-1), re = (1< cR) continue; int target; if (len == 1) target = END; else target = gr(len-1, cL - rs, cR - rs); if (target != -1) adj[START].push_back({target, 1}); } // Phase 2: Compute reachability from START vector reach(n, false); { queue q; q.push(START); reach[START] = true; while (!q.empty()) { int u = q.front(); q.pop(); for (auto& e : adj[u]) { if (!reach[e.to]) { reach[e.to] = true; q.push(e.to); } } } } // Phase 3: ADFA minimization - merge nodes with identical subtrees // Compute signature for each node bottom-up (topological order) // Signature = sorted list of (child_signature, weight) pairs // Compute topological order (reverse BFS from END, or compute in-degrees) // Actually, let's use the fact that this is a layered DAG. // We'll compute signatures bottom-up. // First, compute depth of each node (longest path from node to END) vector depth(n, -1); depth[END] = 0; // BFS in reverse topological order // Let's compute topological order first vector indeg(n, 0); for (int u = 0; u < n; u++) { if (!reach[u]) continue; for (auto& e : adj[u]) { indeg[e.to]++; } } vector topo; queue q; for (int u = 0; u < n; u++) { if (reach[u] && indeg[u] == 0) q.push(u); } while (!q.empty()) { int u = q.front(); q.pop(); topo.push_back(u); for (auto& e : adj[u]) { if (--indeg[e.to] == 0) q.push(e.to); } } // Reverse topological order for bottom-up processing reverse(topo.begin(), topo.end()); // Compute canonical signature for each node // Map signature -> representative node map>, int> sig_to_rep; // signature -> representative vector node_rep(n, -1); // node -> its representative for (int u : topo) { if (!reach[u]) continue; // Build signature using representative IDs of children vector> sig; for (auto& e : adj[u]) { sig.push_back({node_rep[e.to], e.w}); } sort(sig.begin(), sig.end()); auto it = sig_to_rep.find(sig); if (it != sig_to_rep.end()) { node_rep[u] = it->second; } else { node_rep[u] = u; sig_to_rep[sig] = u; } } // But wait - START must remain START (can't merge with anything else due to its role) // And END must remain END. // Actually, the merging is fine as long as we track which nodes survive. // However, there's a subtlety: we can't merge START with anything because it's the // unique in-degree-0 node. Similarly END is the unique out-degree-0 node. // The signature-based merging handles this naturally if signatures are truly identical. // Collect unique representative nodes set reps; for (int u : topo) { if (reach[u]) reps.insert(node_rep[u]); } // Assign new IDs. START must be first. map new_id; int cnt = 0; new_id[node_rep[START]] = ++cnt; for (int r : reps) { if (r != node_rep[START]) { new_id[r] = ++cnt; } } // Build output adjacency vector>> out_adj(cnt + 1); for (int r : reps) { int id = new_id[r]; for (auto& e : adj[r]) { int child_rep = node_rep[e.to]; out_adj[id].push_back({new_id[child_rep], e.w}); } // Deduplicate edges sort(out_adj[id].begin(), out_adj[id].end()); out_adj[id].erase(unique(out_adj[id].begin(), out_adj[id].end()), out_adj[id].end()); } cout << cnt << "\n"; for (int i = 1; i <= cnt; i++) { cout << out_adj[i].size(); for (auto& [to, w] : out_adj[i]) { cout << " " << to << " " << w; } cout << "\n"; } return 0; }