File size: 3,535 Bytes
1fd0050 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | #include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long L, R;
if (!(cin >> L >> R)) return 0;
// Decompose [L, R] into dyadic intervals (b, k) where size = 2^k and b divisible by 2^k
struct Interval { long long b; int k; };
vector<Interval> intervals;
long long cur = L;
int M = 0; // maximum k among intervals
while (cur <= R) {
int tz = __builtin_ctzll(cur); // trailing zeros
long long rem = R - cur + 1;
int maxk = 63 - __builtin_clzll(rem); // floor(log2(rem))
int k = min(tz, maxk);
intervals.push_back({cur, k});
M = max(M, k);
cur += 1LL << k;
}
// Graph structures
// Node 1: start, Node 2: sink
vector<vector<pair<int,int>>> adj; // adj[u] = list of (v,label)
vector<array<int,2>> contNext; // designated continuation edges for building prefixes (per label)
adj.resize(3); // 1-based, start with 2 nodes
contNext.resize(3);
contNext[1] = {0,0};
contNext[2] = {0,0};
int S = 1, T = 2;
int nNodes = 2;
auto newNode = [&]() {
++nNodes;
adj.resize(nNodes+1);
contNext.resize(nNodes+1);
contNext[nNodes] = {0,0};
return nNodes;
};
unordered_set<long long> edgeSet;
edgeSet.reserve(4096);
auto addEdge = [&](int u, int v, int w){
long long key = ((long long)u << 40) ^ ((long long)v << 1) ^ (long long)w;
if (edgeSet.insert(key).second) {
adj[u].push_back({v, w});
}
};
// Build shared free-bits chain of length M (G[0..M-1]) towards sink
vector<int> G; // G[i] where distance to sink in edges = M - i
if (M > 0) {
G.resize(M);
for (int i = 0; i < M; ++i) {
G[i] = newNode();
}
for (int i = 0; i < M-1; ++i) {
addEdge(G[i], G[i+1], 0);
addEdge(G[i], G[i+1], 1);
}
addEdge(G[M-1], T, 0);
addEdge(G[M-1], T, 1);
}
auto bitlen = [&](long long x)->int{
return (x == 0) ? 0 : (64 - __builtin_clzll(x));
};
// Process each interval
for (auto itv : intervals) {
long long b = itv.b;
int k = itv.k;
long long p = b >> k; // prefix
int lenp = bitlen(p);
int curNode = S;
for (int i = lenp - 1; i >= 0; --i) {
int bit = (p >> i) & 1;
if (i == 0 && k == 0) {
// last bit and no free bits: direct to sink with this bit
addEdge(curNode, T, bit);
} else {
// ensure continuation edge for this bit to next prefix node
if (contNext[curNode][bit] == 0) {
int nx = newNode();
addEdge(curNode, nx, bit);
contNext[curNode][bit] = nx;
}
curNode = contNext[curNode][bit];
}
}
if (k > 0) {
int target = G[M - k]; // node from which exactly k-1 steps then last to sink remain
// from the prefix node, the next bit (first free bit) can be 0 or 1 to 'target'
addEdge(curNode, target, 0);
addEdge(curNode, target, 1);
}
}
// Output
cout << nNodes << '\n';
for (int u = 1; u <= nNodes; ++u) {
cout << (int)adj[u].size();
for (auto &e : adj[u]) {
cout << ' ' << e.first << ' ' << e.second;
}
cout << '\n';
}
return 0;
} |