import java.awt.Point;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
/** Google Code Jam 2013, wrong code for round 1B, problem B */
class B {
init();
int T
= Integer.
parseInt(br.
readLine()); for (int ii = 0; ii < T; ii++) {
line = br.readLine();
int N, X, Y;
N
= Integer.
parseInt(tok.
nextToken()); X
= Integer.
parseInt(tok.
nextToken()); Y
= Integer.
parseInt(tok.
nextToken()); System.
out.
printf("Case #%d: %.9f\n", ii
+1, solve
(N, X, Y
)); }
}
static HashMap
<Integer, HashMap
<Point, Double
>> data
= new HashMap
<>();
public static void init() {
HashMap
<Point, Double
> n1map
= new HashMap
<>(); n1map.
put(new Point(0,
0), 1D
); data.put(1, n1map);
data.put(6, getN6());
data.put(15, getN15());
}
private static HashMap
<Point, Double
> getN6
() { HashMap
<Point, Double
> res
= new HashMap
<>(); res.putAll(data.get(1));
int x = -2;
int y = 0;
res.
put(new Point(x, y
), 1D
); for (int i = 0; i < 2; i++) {
++x;
++y;
res.
put(new Point(x, y
), 1D
); }
for (int i = 0; i < 2; i++) {
++x;
--y;
res.
put(new Point(x, y
), 1D
); }
return res;
}
private static HashMap
<Point, Double
> getN15
() { HashMap
<Point, Double
> res
= new HashMap
<>(); res.putAll(data.get(6));
int x = -4;
int y = 0;
res.
put(new Point(x, y
), 1D
); for (int i = 0; i < 3; i++) {
++x;
++y;
res.
put(new Point(x, y
), 1D
); }
for (int i = 0; i < 3; i++) {
++x;
--y;
res.
put(new Point(x, y
), 1D
); }
return res;
}
public static double solve(int N, int X, int Y) {
Set<Integer> special = new HashSet<Integer>(); special.add(1); special.add(6); special.add(15);
HashMap
<Point, Double
> map
; if (special.contains(N)) {
map = data.get(N);
} else {
if (data.containsKey(N)) {
map = data.get(N);
} else {
if (N > 15) {
map = get(15, N - 15, 6);
} else if (N > 6 ) {
map = get(6, N - 6, 4);
} else {
map = get(1, N - 1, 2);
}
data.put(N, map);
}
}
return res == null ? 0 : res;
}
private static HashMap
<Point, Double
> get
(int SN,
int cnt,
int max
) { // SN = special N
HashMap
<Point, Double
> res
= new HashMap
<>(); int pos = 0;
for (int mask = 0; mask < (1 << cnt); mask++) {
int lc = cnt - rc;
if (rc > max || lc > max ) {
continue;
}
++pos;
for (int i = 0; i < lc; i++) {
Point p
= getLeft
(SN, i
); inc(p, res);
}
for (int i = 0; i < rc; i++) {
Point p
= getRight
(SN, i
); inc(p, res);
}
}
// divide by pos
//System.out.printf( "DEBUG: pos=%d\n", pos );
for (Point p
: res.
keySet()) { double prob = res.get(p);
res.put(p, prob / pos);
}
// add special points
res.putAll(data.get(SN));
return res;
}
private static Point getLeft
(int SN,
int idx
) { int y = 0;
int x;
switch(SN) {
case 1: x = -2; break;
case 6: x = -4; break;
case 15: x = -6; break;
}
for (int i = 0; i < idx; i++) {
++y;
++x;
}
}
private static Point getRight
(int SN,
int idx
) { int y = 0;
int x;
switch(SN) {
case 1: x = 2; break;
case 6: x = 4; break;
case 15: x = 6; break;
}
for (int i = 0; i < idx; i++) {
++y;
--x;
}
}
private static void inc
(Point p, Map
<Point, Double
> map
) { if (val == null) val = 0D;
map.put(p, val + 1);
}
}
aW1wb3J0IGphdmEuYXd0LlBvaW50OwppbXBvcnQgamF2YS5pby5CdWZmZXJlZFJlYWRlcjsKaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW1SZWFkZXI7CmltcG9ydCBqYXZhLnV0aWwuSGFzaE1hcDsKaW1wb3J0IGphdmEudXRpbC5IYXNoU2V0OwppbXBvcnQgamF2YS51dGlsLk1hcDsKaW1wb3J0IGphdmEudXRpbC5TZXQ7CmltcG9ydCBqYXZhLnV0aWwuU3RyaW5nVG9rZW5pemVyOwoKLyoqIEdvb2dsZSBDb2RlIEphbSAyMDEzLCB3cm9uZyBjb2RlIGZvciByb3VuZCAxQiwgcHJvYmxlbSBCICovCmNsYXNzIEIgewoKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHRocm93cyBFeGNlcHRpb24gewogICAgCWluaXQoKTsKCQkKCQlCdWZmZXJlZFJlYWRlciBiciA9IG5ldyBCdWZmZXJlZFJlYWRlcihuZXcgSW5wdXRTdHJlYW1SZWFkZXIoU3lzdGVtLmluKSk7CgkJaW50IFQgPSBJbnRlZ2VyLnBhcnNlSW50KGJyLnJlYWRMaW5lKCkpOwoJCVN0cmluZyBsaW5lOwoJCVN0cmluZ1Rva2VuaXplciB0b2s7CgkJZm9yIChpbnQgaWkgPSAwOyBpaSA8IFQ7IGlpKyspIHsKCQkJbGluZSA9IGJyLnJlYWRMaW5lKCk7CgkJCXRvayA9IG5ldyBTdHJpbmdUb2tlbml6ZXIobGluZSk7CgkJCWludCBOLCBYLCBZOwoJCQlOID0gSW50ZWdlci5wYXJzZUludCh0b2submV4dFRva2VuKCkpOwoJCQlYID0gSW50ZWdlci5wYXJzZUludCh0b2submV4dFRva2VuKCkpOwoJCQlZID0gSW50ZWdlci5wYXJzZUludCh0b2submV4dFRva2VuKCkpOwoJCQlTeXN0ZW0ub3V0LnByaW50ZigiQ2FzZSAjJWQ6ICUuOWZcbiIsIGlpKzEsIHNvbHZlKE4sIFgsIFkpKTsKCQl9Cgl9CgoJc3RhdGljIEhhc2hNYXA8SW50ZWdlciwgSGFzaE1hcDxQb2ludCwgRG91YmxlPj4gZGF0YSA9IG5ldyBIYXNoTWFwPD4oKTsKCglwdWJsaWMgc3RhdGljIHZvaWQgaW5pdCgpIHsKCQlIYXNoTWFwPFBvaW50LCBEb3VibGU+IG4xbWFwID0gbmV3IEhhc2hNYXA8PigpOwoJCW4xbWFwLnB1dChuZXcgUG9pbnQoMCwgMCksICAxRCk7CgkJZGF0YS5wdXQoMSwgbjFtYXApOwoJCQoJCWRhdGEucHV0KDYsIGdldE42KCkpOwoKCQlkYXRhLnB1dCgxNSwgZ2V0TjE1KCkpOwoJfQoKCXByaXZhdGUgc3RhdGljIEhhc2hNYXA8UG9pbnQsIERvdWJsZT4gZ2V0TjYoKSB7CgkJSGFzaE1hcDxQb2ludCwgRG91YmxlPiByZXMgPSBuZXcgSGFzaE1hcDw+KCk7CgkJcmVzLnB1dEFsbChkYXRhLmdldCgxKSk7CgkJaW50IHggPSAtMjsKCQlpbnQgeSA9IDA7CgkJcmVzLnB1dChuZXcgUG9pbnQoeCwgeSksIDFEKTsKCQlmb3IgKGludCBpID0gMDsgaSA8IDI7IGkrKykgewoJCQkrK3g7CgkJCSsreTsKCQkJcmVzLnB1dChuZXcgUG9pbnQoeCwgeSksIDFEKTsKCQl9CgkJZm9yIChpbnQgaSA9IDA7IGkgPCAyOyBpKyspIHsKCQkJKyt4OwoJCQktLXk7CgkJCXJlcy5wdXQobmV3IFBvaW50KHgsIHkpLCAxRCk7CgkJfQoJCXJldHVybiByZXM7Cgl9CgoJcHJpdmF0ZSBzdGF0aWMgSGFzaE1hcDxQb2ludCwgRG91YmxlPiBnZXROMTUoKSB7CgkJSGFzaE1hcDxQb2ludCwgRG91YmxlPiByZXMgPSBuZXcgSGFzaE1hcDw+KCk7CgkJcmVzLnB1dEFsbChkYXRhLmdldCg2KSk7CgkJaW50IHggPSAtNDsKCQlpbnQgeSA9IDA7CgkJcmVzLnB1dChuZXcgUG9pbnQoeCwgeSksIDFEKTsKCQlmb3IgKGludCBpID0gMDsgaSA8IDM7IGkrKykgewoJCQkrK3g7CgkJCSsreTsKCQkJcmVzLnB1dChuZXcgUG9pbnQoeCwgeSksIDFEKTsKCQl9CgkJZm9yIChpbnQgaSA9IDA7IGkgPCAzOyBpKyspIHsKCQkJKyt4OwoJCQktLXk7CgkJCXJlcy5wdXQobmV3IFBvaW50KHgsIHkpLCAxRCk7CgkJfQoJCXJldHVybiByZXM7Cgl9CgoJcHVibGljIHN0YXRpYyBkb3VibGUgc29sdmUoaW50IE4sIGludCBYLCBpbnQgWSkgewoJCVNldDxJbnRlZ2VyPiBzcGVjaWFsID0gbmV3IEhhc2hTZXQ8SW50ZWdlcj4oKTsgc3BlY2lhbC5hZGQoMSk7IHNwZWNpYWwuYWRkKDYpOyBzcGVjaWFsLmFkZCgxNSk7CgkJSGFzaE1hcDxQb2ludCwgRG91YmxlPiBtYXA7CgkJaWYgKHNwZWNpYWwuY29udGFpbnMoTikpIHsKCQkJbWFwID0gZGF0YS5nZXQoTik7CgkJfSBlbHNlIHsKCQkJaWYgKGRhdGEuY29udGFpbnNLZXkoTikpIHsKCQkJCW1hcCA9IGRhdGEuZ2V0KE4pOwoJCQl9IGVsc2UgewoJCQkJaWYgKE4gPiAxNSkgewoJCQkJCW1hcCA9IGdldCgxNSwgTiAtIDE1LCA2KTsKCQkJCX0gZWxzZSBpZiAoTiA+IDYgKSB7CgkJCQkJbWFwID0gZ2V0KDYsIE4gLSA2LCA0KTsKCQkJCX0gZWxzZSB7CgkJCQkJbWFwID0gZ2V0KDEsIE4gLSAxLCAyKTsKCQkJCX0KCQkJCWRhdGEucHV0KE4sIG1hcCk7CgkJCX0KCQl9CgkJRG91YmxlIHJlcyA9IG1hcC5nZXQobmV3IFBvaW50KFgsIFkpKTsKCQlyZXR1cm4gcmVzID09IG51bGwgPyAwIDogcmVzOwoJfQoKCXByaXZhdGUgc3RhdGljIEhhc2hNYXA8UG9pbnQsIERvdWJsZT4gZ2V0KGludCBTTiwgaW50IGNudCwgaW50IG1heCkgewoJCS8vIFNOID0gc3BlY2lhbCBOCgkJSGFzaE1hcDxQb2ludCwgRG91YmxlPiByZXMgPSBuZXcgSGFzaE1hcDw+KCk7CgkJaW50IHBvcyA9IDA7CgkJZm9yIChpbnQgbWFzayA9IDA7IG1hc2sgPCAoMSA8PCBjbnQpOyBtYXNrKyspIHsKCQkJaW50IHJjID0gSW50ZWdlci5iaXRDb3VudChtYXNrKTsKCQkJaW50IGxjID0gY250IC0gcmM7CgkJCWlmIChyYyA+IG1heCB8fCBsYyA+IG1heCApIHsKCQkJCWNvbnRpbnVlOwoJCQl9CgkJCSsrcG9zOwoJCQlmb3IgKGludCBpID0gMDsgaSA8IGxjOyBpKyspIHsKCQkJCVBvaW50IHAgPSBnZXRMZWZ0KFNOLCBpKTsKCQkJCWluYyhwLCByZXMpOwoJCQl9CgkJCWZvciAoaW50IGkgPSAwOyBpIDwgcmM7IGkrKykgewoJCQkJUG9pbnQgcCA9IGdldFJpZ2h0KFNOLCBpKTsKCQkJCWluYyhwLCByZXMpOwoJCQl9CgkJfQoJCS8vIGRpdmlkZSBieSBwb3MKCQkvL1N5c3RlbS5vdXQucHJpbnRmKCAiREVCVUc6IHBvcz0lZFxuIiwgcG9zICk7CgkJZm9yIChQb2ludCBwIDogcmVzLmtleVNldCgpKSB7CgkJCWRvdWJsZSBwcm9iID0gcmVzLmdldChwKTsKCQkJcmVzLnB1dChwLCBwcm9iIC8gcG9zKTsKCQl9CgkJLy8gYWRkIHNwZWNpYWwgcG9pbnRzCgkJcmVzLnB1dEFsbChkYXRhLmdldChTTikpOwoJCXJldHVybiByZXM7Cgl9CgoJcHJpdmF0ZSBzdGF0aWMgUG9pbnQgZ2V0TGVmdChpbnQgU04sIGludCBpZHgpIHsKCQlpbnQgeSA9IDA7CgkJaW50IHg7CgkJc3dpdGNoKFNOKSB7CgkJY2FzZSAxOiB4ID0gLTI7IGJyZWFrOwoJCWNhc2UgNjogeCA9IC00OyBicmVhazsKCQljYXNlIDE1OiB4ID0gLTY7IGJyZWFrOwoJCWRlZmF1bHQ6IHRocm93IG5ldyBJbGxlZ2FsQXJndW1lbnRFeGNlcHRpb24oIlNOPSIgKyBTTik7CgkJfQoJCWZvciAoaW50IGkgPSAwOyBpIDwgaWR4OyBpKyspIHsKCQkJKyt5OwoJCQkrK3g7CgkJfQoJCXJldHVybiBuZXcgUG9pbnQoeCwgeSk7Cgl9CgoJcHJpdmF0ZSBzdGF0aWMgUG9pbnQgZ2V0UmlnaHQoaW50IFNOLCBpbnQgaWR4KSB7CgkJaW50IHkgPSAwOwoJCWludCB4OwoJCXN3aXRjaChTTikgewoJCWNhc2UgMTogeCA9IDI7IGJyZWFrOwoJCWNhc2UgNjogeCA9IDQ7IGJyZWFrOwoJCWNhc2UgMTU6IHggPSA2OyBicmVhazsKCQlkZWZhdWx0OiB0aHJvdyBuZXcgSWxsZWdhbEFyZ3VtZW50RXhjZXB0aW9uKCJTTj0iICsgU04pOwoJCX0KCQlmb3IgKGludCBpID0gMDsgaSA8IGlkeDsgaSsrKSB7CgkJCSsreTsKCQkJLS14OwoJCX0KCQlyZXR1cm4gbmV3IFBvaW50KHgsIHkpOwoJfQoKCXByaXZhdGUgc3RhdGljIHZvaWQgaW5jKFBvaW50IHAsIE1hcDxQb2ludCwgRG91YmxlPiBtYXApIHsKCQlEb3VibGUgdmFsID0gbWFwLmdldChwKTsKCQlpZiAodmFsID09IG51bGwpIHZhbCA9IDBEOwoJCW1hcC5wdXQocCwgdmFsICsgMSk7Cgl9Cgp9Cg==