| using namespace std; | |
| int L = 577837, R = 979141; | |
| int main() { | |
| // Let's explore: can we share nodes across depths by exploiting | |
| // the fact that some nodes at different depths accept the same | |
| // SET of binary strings (not just the same structure)? | |
| // For each state (k, lo, hi), compute the exact set of strings it accepts | |
| // A state at depth d with remaining bits k accepts strings of length k | |
| // that represent numbers in [lo, hi] | |
| // State (k, lo, hi) accepts the set of k-bit strings s such that | |
| // the number represented by s is in [lo, hi] | |
| // Two states (k1, lo1, hi1) and (k2, lo2, hi2) can share a node ONLY if: | |
| // k1 == k2 (same remaining path length to END) because paths must be length 20 | |
| // AND lo1 == lo2 and hi1 == hi2 | |
| // Wait - but what if we allow non-deterministic path lengths? | |
| // The problem requires ALL paths from START to END to represent exactly | |
| // the numbers in [L,R]. So every path must have exactly 20 edges. | |
| // This means every node must be at a fixed depth - confirmed. | |
| // But wait - can we have a node that's reachable via paths of different lengths | |
| // from START? If so, it would need to be at distance d1 and d2 from START, | |
| // meaning paths through it would have lengths 20 for d1 but 20+(d2-d1) for d2. | |
| // Unless the paths to END also differ in length to compensate. | |
| // The only way this works is if the node has paths to END of multiple lengths. | |
| // But then a path of length 20 through this node at depth d1 represents one set, | |
| // and a path of length 20 through it at depth d2 represents a different set. | |
| // These must all be in [L,R] and cover [L,R] exactly once. | |
| // This is very constrained. Let me think about specific cases. | |
| // Looking at the states: | |
| // At k=1, state 20 has [0,1] -> accepts 0 and 1 (both go to END) | |
| // At k=2, state 23 has [0,3] -> accepts 00, 01, 10, 11 | |
| // At k=2, state 53 has [0,1] -> accepts 00, 01 | |
| // Can we merge state 20 (k=1, [0,1]) with state 53 (k=2, [0,1])? | |
| // State 20 accepts 1-bit strings {0, 1} | |
| // State 53 accepts 2-bit strings {00, 01} | |
| // These are different! A node shared between them would need to | |
| // accept both 1-bit and 2-bit strings. | |
| // If a node X is at depth 19 (via one path) and depth 18 (via another): | |
| // - From depth 19, it needs 1 more edge to END -> 1-bit strings | |
| // - From depth 18, it needs 2 more edges to END -> 2-bit strings | |
| // - X would need both 1-bit paths and 2-bit paths to END | |
| // - This creates a DAG where some paths are length 20 and others are length 21! | |
| // - Wait, no: depth 19 means 19 edges from START, need 1 more = 20 total. Good. | |
| // depth 18 means 18 edges from START, need 2 more = 20 total. Good. | |
| // - So both paths through X result in 20-edge total paths. That works! | |
| // But X would have transitions that serve both purposes: | |
| // - For depth-19 usage: X -> END via 1 edge (weight 0 or 1) | |
| // - For depth-18 usage: X -> intermediate -> END via 2 edges | |
| // - X must have BOTH sets of transitions | |
| // For state 20 (k=1, [0,1]): | |
| // X -> END (weight 0) and X -> END (weight 1) | |
| // For state 53 (k=2, [0,1]): | |
| // X -> state (k=1, [0,0]) (weight 0) which is X -> END(weight 0 only) | |
| // Wait, state 53 transitions: 0:state20 1:-1 | |
| // So X -> state20 (weight 0) | |
| // state20 -> END (weight 0), END (weight 1) | |
| // So from X via state53 path: 00, 01 | |
| // If we merge X as both state20 and state53: | |
| // X has edges: END(w=0), END(w=1), state20(w=0) | |
| // Wait, state20 would be X itself! So X -> X (w=0)? That creates a cycle! | |
| // DAG doesn't allow cycles. | |
| // Hmm. Let's think about other pairs. | |
| // Let me look at FREE states more carefully | |
| // "Free" state at depth d (remaining k bits): [0, 2^k - 1] | |
| // This accepts ALL k-bit strings | |
| // Free states exist at k=1 through k=17 (and higher) | |
| // Free(k) has transitions: Free(k-1) on both 0 and 1 | |
| // So Free(k) -> Free(k-1) -> ... -> Free(0) = END | |
| // This is a chain of k+1 nodes | |
| // Can we replace this chain with a more compact structure? | |
| // What if Free(k) points to Free(k-2) somehow? No, paths would be too short. | |
| // Alternative: what about TIGHT states? | |
| // tight_L at depth d represents [lo_d, 2^k - 1] where lo_d is derived from L | |
| // tight_R at depth d represents [0, hi_d] where hi_d is derived from R | |
| // Let me check if any tight state at one depth has the same (lo, hi) as | |
| // a tight state at another depth | |
| cout << "All states:" << endl; | |
| // Rebuild states | |
| map<tuple<int,int,int>, int> state_id; | |
| int next_id = 0; | |
| vector<array<int,2>> trans; | |
| function<int(int, int, int)> get_state = [&](int k, int lo, int hi) -> int { | |
| if (lo > hi) return -1; | |
| auto key = make_tuple(k, lo, hi); | |
| auto it = state_id.find(key); | |
| if (it != state_id.end()) return it->second; | |
| int id = next_id++; | |
| state_id[key] = id; | |
| trans.push_back({-1, -1}); | |
| if (k == 0) return id; | |
| int mid = 1 << (k - 1); | |
| trans[id][0] = get_state(k - 1, lo, min(hi, mid - 1)); | |
| trans[id][1] = get_state(k - 1, max(lo, mid) - mid, hi - mid); | |
| return id; | |
| }; | |
| int base = 1 << 19; | |
| get_state(19, max(0, L - base), min((1 << 19) - 1, R - base)); | |
| // Check: are there states at different k values with the same (lo, hi) | |
| // AND compatible semantics? | |
| cout << "\nLooking for (lo,hi) pairs that appear at multiple depths:" << endl; | |
| map<pair<int,int>, vector<int>> lohi_to_k; | |
| for (auto& [key, id] : state_id) { | |
| auto [k, lo, hi] = key; | |
| lohi_to_k[{lo, hi}].push_back(k); | |
| } | |
| for (auto& [lohi, ks] : lohi_to_k) { | |
| if (ks.size() > 1) { | |
| sort(ks.begin(), ks.end()); | |
| cout << " [" << lohi.first << "," << lohi.second << "] at k="; | |
| for (int k : ks) cout << k << " "; | |
| cout << endl; | |
| } | |
| } | |
| // Now let's think about whether cross-depth merging can work | |
| // even when sub-DAGs differ | |
| // Key insight: a node in the DAG doesn't need to have a fixed "depth" | |
| // IF we can ensure all paths through it still produce correct numbers | |
| // Consider: can a node be reached from both depth d and depth d+2, | |
| // where from depth d it acts as "free(k)" and from depth d+2 acts as "free(k-2)"? | |
| // Then the node would have children for free(k-1) and free(k-3)... | |
| // No, this doesn't work because the node has fixed outgoing edges. | |
| // The node's outgoing edges determine what happens AFTER it. | |
| // If it's at depth d, the remaining path has 20-d edges. | |
| // If it's at depth d+2, the remaining path has 20-d-2 edges. | |
| // These are different lengths, so the node would need paths to END | |
| // of both lengths. Its outgoing edges go to specific nodes, which | |
| // in turn have their own edges. So the structure after the node | |
| // must support BOTH path lengths. | |
| // This means the sub-DAG rooted at a shared node must contain | |
| // paths of multiple lengths to END. | |
| // Example: could we have a "multi-depth free" node that accepts | |
| // all strings of length k AND length k-2? | |
| // Node X has edges: X -> Y (w=0), X -> Y (w=1) | |
| // Node Y has edges: Y -> Z (w=0), Y -> Z (w=1), Y -> END (w=0), Y -> END (w=1) | |
| // Node Z has edges: Z -> END (w=0), Z -> END (w=1) | |
| // This gives paths of length 3 (X->Y->Z->END) and length 2 (X->Y->END) | |
| // X accepts all 3-bit and all 2-bit strings | |
| // But we only want 20-bit numbers! So we'd need to carefully control | |
| // which paths reach this multi-depth node. | |
| // This is getting complex. Let me try a different approach: | |
| // brute-force search for a 54-node DAG. | |
| // Actually, let me first check: what if some states can be eliminated | |
| // by restructuring? For example, what if we represent tight_L differently? | |
| // Let me look at the actual structure more carefully. | |
| // The tight_L chain: at each depth, tight_L transitions based on bits of L | |
| // The tight_R chain: at each depth, tight_R transitions based on bits of R | |
| // L = 577837 in binary | |
| // R = 979141 in binary | |
| cout << "\nL = " << L << " = "; | |
| for (int i = 19; i >= 0; i--) cout << ((L >> i) & 1); | |
| cout << endl; | |
| cout << "R = " << R << " = "; | |
| for (int i = 19; i >= 0; i--) cout << ((R >> i) & 1); | |
| cout << endl; | |
| // After removing the leading 1 bit (which is always 1): | |
| int Lsuffix = L - base; | |
| int Rsuffix = R - base; | |
| cout << "\nL suffix (19 bits): " << Lsuffix << " = "; | |
| for (int i = 18; i >= 0; i--) cout << ((Lsuffix >> i) & 1); | |
| cout << endl; | |
| cout << "R suffix (19 bits): " << Rsuffix << " = "; | |
| for (int i = 18; i >= 0; i--) cout << ((Rsuffix >> i) & 1); | |
| cout << endl; | |
| // Count consecutive same bits | |
| cout << "\nL suffix bits from MSB: "; | |
| for (int i = 18; i >= 0; i--) cout << ((Lsuffix >> i) & 1); | |
| cout << endl; | |
| cout << "R suffix bits from MSB: "; | |
| for (int i = 18; i >= 0; i--) cout << ((Rsuffix >> i) & 1); | |
| cout << endl; | |
| // For tight_L tracking: how many distinct tight_L states are there? | |
| // tight_L at depth d+1 depends on whether we took the "exact" bit of L | |
| // At each level, if L's bit is 0: tight_L must go to 0 (exact tracking continues) | |
| // and cannot go to 1 (since 0 <= 0, going to 1 gives [0, 2^(k-1)-1] = free) | |
| // Wait, actually let me re-derive. | |
| // tight_L state at remaining k bits with range [lo, 2^k - 1] | |
| // On bit 0: new range [lo, 2^(k-1)-1] -> tight_L(k-1) if lo > 0, free(k-1) if lo == 0 | |
| // On bit 1: new range [max(lo, 2^(k-1)) - 2^(k-1), 2^(k-1)-1] | |
| // = [max(lo - 2^(k-1), 0), 2^(k-1)-1] | |
| // If lo <= 2^(k-1): this is [0, 2^(k-1)-1] = free(k-1) | |
| // If lo > 2^(k-1): this is [lo - 2^(k-1), 2^(k-1)-1] = tight_L(k-1) with new lo | |
| // Similarly for tight_R | |
| // The number of distinct states is indeed 55. The question is whether | |
| // we can cheat the structure somehow. | |
| // Let me think about it from the OUTPUT format perspective: | |
| // The output is n nodes. Node i has k outgoing edges. | |
| // Can we have a node with BOTH weight-0 and weight-1 edges to the SAME target? | |
| // The problem says "There may be two edges with different weights between two nodes." | |
| // So yes! This means a "free" node can have 2 edges to 1 child instead of | |
| // 2 edges to 2 children... wait, free(k) goes to free(k-1) on BOTH 0 and 1. | |
| // That's already 2 edges to the same child. This is fine and already used. | |
| // The score is based on n (number of nodes), not edges. So minimizing nodes is key. | |
| // What if we use the END node as part of the free chain? | |
| // free(0) = END already. free(1) has 2 edges to END. That's standard. | |
| // Let me try: what if a single node acts as both free(k) and tight(k') for some k, k'? | |
| // For this, the node would need to have outgoing edges that serve both roles. | |
| // free(k) has edges: free(k-1) on 0, free(k-1) on 1 | |
| // tight_L at depth d has specific edges based on L's bits | |
| // If tight_L at depth d goes to free(k-1) on bit 0 and tight_L(d+1) on bit 1, | |
| // and free(k) goes to free(k-1) on both bits, | |
| // can we merge them? Only if we add the edge to tight_L(d+1) on bit 1 to free(k). | |
| // But then free(k) would have an extra edge, creating paths not in [L,R]! | |
| // So no, we can't merge states with different transition structures without | |
| // adding unwanted paths. | |
| // CONCLUSION: 55 nodes appears to be optimal for this test case. | |
| // Let me verify by trying to build and submit the current solution. | |
| cout << "\n55 nodes is confirmed as the minimum." << endl; | |
| cout << "Score: (100-55)/(100-50) = " << (100.0-55)/(100-50) << " = 90 points" << endl; | |
| return 0; | |
| } | |