1 import java
.io
.FileReader
;
2 import java
.io
.IOException
;
3 import java
.io
.PrintWriter
;
4 import java
.util
.Scanner
;
6 public class kequiv_mb
implements Runnable
{
8 private PrintWriter out
;
10 public static final int MAX_LENGTH
= 20;
11 public static final int NUM_DIGITS
= 10;
12 private DigitTrie trie
;
14 static class TrieNode
{
16 public TrieNode parent
;
17 public TrieNode
[] links
;
18 public boolean isLeaf
;
21 static interface TrieNodeProcessor
{
22 boolean process(short[] digits
, int length
);
25 static class DigitTrie
{
26 private final TrieNode root
= new TrieNode();
28 public void insert(short[] digits
, int length
) {
29 //System.out.print("insert: ");
30 //dumpDigits(digits, length);
31 //System.out.println();
34 for (int i
= 0; i
< length
; i
++) {
38 int digit
= digits
[i
];
39 if (node
.links
== null) {
40 node
.links
= new TrieNode
[NUM_DIGITS
];
42 if (node
.links
[digit
] == null) {
43 final TrieNode newNode
= new TrieNode();
44 newNode
.parent
= node
;
45 node
.links
[digit
] = newNode
;
48 node
= node
.links
[digit
];
51 while (node
!= null) {
57 public boolean contains(short[] digits
, int length
) {
59 for (int i
= 0; i
< length
; i
++) {
63 int digit
= digits
[i
];
64 node
= node
.links
[digit
];
72 public void enumerate(TrieNodeProcessor processor
) {
73 short[] digits
= new short[MAX_LENGTH
];
74 enumerate(processor
, root
, digits
, 0);
77 private boolean enumerate(TrieNodeProcessor processor
, TrieNode node
, short[] digits
, int length
) {
79 return processor
.process(digits
, length
);
82 if (node
.links
== null) {
86 for (int digit
= 0; digit
< 10; digit
++) {
87 if (node
.links
[digit
] != null) {
88 digits
[length
] = (short) digit
;
89 if (!enumerate(processor
, node
.links
[digit
], digits
, length
+ 1)) {
97 private void optimize(TrieNode node
) {
98 if (node
.numLinks
!= NUM_DIGITS
) {
102 for (int i
= 0; i
< NUM_DIGITS
; i
++) {
103 if (node
.links
[i
].isLeaf
) {
107 if (numLeafs
== NUM_DIGITS
) {
112 private void makeLeaf(TrieNode node
) {
118 public static void main(String
[] args
) {
119 new Thread(new kequiv_mb()).start();
124 in
= new Scanner(new FileReader("kequiv.in"));
125 out
= new PrintWriter("kequiv.out");
131 } catch (IOException e
) {
136 private static void dumpDigits(short[] digits
, int length
) {
137 for (int i
= 0; i
< length
; i
++) {
138 System
.out
.print(digits
[i
]);
140 for (int i
= 0; i
< MAX_LENGTH
- length
; i
++) {
141 System
.out
.print("?");
145 private short[] toDigits(long value
) {
146 short[] result
= new short[MAX_LENGTH
];
147 for (int i
= 0; i
< MAX_LENGTH
; i
++) {
148 result
[i
] = (short) (value
% 10);
151 for (int i
= 0; i
< MAX_LENGTH
/ 2; i
++) {
152 short tmp
= result
[i
];
153 result
[i
] = result
[MAX_LENGTH
- i
- 1];
154 result
[MAX_LENGTH
- i
- 1] = tmp
;
159 private void insertRange(DigitTrie trie
, long lo
, long hi
) {
160 final short[] loDigits
= toDigits(lo
);
161 final short[] hiDigits
= toDigits(hi
);
163 while (i
< MAX_LENGTH
&& loDigits
[i
] == hiDigits
[i
]) {
167 trie
.insert(loDigits
, MAX_LENGTH
);
168 trie
.insert(hiDigits
, MAX_LENGTH
);
170 if (i
== MAX_LENGTH
) {
174 for (int j
= i
+ 1; j
< MAX_LENGTH
; j
++) {
175 short backup
= loDigits
[j
];
176 for (short digit
= (short) (loDigits
[j
] + 1); digit
< NUM_DIGITS
; digit
++) {
178 trie
.insert(loDigits
, j
+ 1);
180 loDigits
[j
] = backup
;
182 backup
= hiDigits
[j
];
183 for (short digit
= (short) (hiDigits
[j
] - 1); digit
>= 0; digit
--) {
185 trie
.insert(hiDigits
, j
+ 1);
187 hiDigits
[j
] = backup
;
190 for (int digit
= loDigits
[i
] + 1; digit
<= hiDigits
[i
] - 1; digit
++) {
191 loDigits
[i
] = (short) digit
;
192 trie
.insert(loDigits
, i
+ 1);
196 static class EquivalenceChecker
implements TrieNodeProcessor
{
197 public boolean isOK
= true;
199 private final DigitTrie trie
;
200 private final short digit1
;
201 private final short digit2
;
203 public EquivalenceChecker(DigitTrie trie
, short digit1
, short digit2
) {
205 this.digit1
= digit1
;
206 this.digit2
= digit2
;
209 public boolean process(short[] digits
, int length
) {
210 for (int i
= 0; i
< length
; i
++) {
211 if (digits
[i
] == digit1
|| digits
[i
] == digit2
) {
212 //System.out.print("check ");
213 //dumpDigits(digits, length);
214 //System.out.print(" to ");
215 final short backupDigit
= digits
[i
];
216 digits
[i
] = (short) (digit1
+ digit2
- digits
[i
]);
217 //dumpDigits(digits, length);
218 isOK
&= trie
.contains(digits
, length
);
219 //System.out.print(" -> ");
220 //System.out.println(isOK);
221 digits
[i
] = backupDigit
;
231 private boolean areEquivalent(final short digit1
, final short digit2
) {
232 if (digit1
== digit2
) {
235 final EquivalenceChecker checker
= new EquivalenceChecker(trie
, digit1
, digit2
);
236 trie
.enumerate(checker
);
240 private void solve() {
241 trie
= new DigitTrie();
242 final int n
= in
.nextInt();
243 for (int i
= 0; i
< n
; i
++) {
244 final long lo
= in
.nextLong();
245 final long hi
= in
.nextLong();
246 insertRange(trie
, lo
, hi
);
250 boolean[] usedDigits
= new boolean[NUM_DIGITS
];
251 for (short i
= 1; i
< NUM_DIGITS
; i
++) {
252 if (!usedDigits
[i
]) {
253 for (short j
= i
; j
< NUM_DIGITS
; j
++) {
254 if (!usedDigits
[j
] && areEquivalent(i
, j
)) {
256 usedDigits
[j
] = true;