public class BichromeSky
{
{
double x, y;
Point(double _x,
double _y
) {
x = _x;
y = _y;
}
{
return new Point(t.
x - x, t.
y - y
); }
double crossProduct
(Point t
) {
return x * t.y - y * t.x;
}
double direction()
{
}
}
class Range
{
double from;
double to;
double prob;
}
double fix(double ang)
{
ang
= ang
* 180 / Math.
PI; while(ang < 0) ang += 360;
while(ang >= 360) ang -= 360;
return ang;
}
{
Range ret = new Range();
for(int i = 0; i < points.length; i++)
{
Point b
= points
[(i
+1)%points.
length]; Point c
= points
[(i
+2)%points.
length]; if(a.to(b).crossProduct(b.to(p)) > 0 && b.to(p).crossProduct(b.to(c)) > 0)
{
ret.
from = fix
(b.
to(p
).
direction() - Math.
PI / 2); }
if(a.to(b).crossProduct(b.to(p)) < 0 && b.to(p).crossProduct(b.to(c)) < 0)
{
ret.
to = fix
(b.
to(p
).
direction() + Math.
PI / 2); }
}
return ret;
}
{
for(int i = 1; i < points.length; i++)
if(points[i].y < points[0].y || (points[i].y == points[0].y && points[i].x < points[0].x))
{
points[0] = points[i];
points[i] = t;
}
for(int iteration = 1; iteration <= points.length; iteration ++)
for(int i = 1; i < points.length-1; i++)
if(points[0].to(points[i]).crossProduct(points[0].to(points[i+1])) < 0)
{
points[i] = points[i+1];
points[i+1] = t;
}
int z = 2;
for(int i = 2; i < points.length; i++)
{
while(points[z-2].to(points[z-1]).crossProduct(points[z-1].to(points[i])) < 0)
z --;
points[z] = points[i];
z ++;
}
for(int i = 0; i < z; i++)
ret[i] = points[i];
return ret;
}
int n;
Range[] r;
double[][][][] dp_mem;
boolean[][][][] done;
double dp(int haveAtLeastOne, int current, int leftIndex, int rightIndex)
{
if(current == n)
return 0.0;
if(done[haveAtLeastOne][current][leftIndex][rightIndex])
return dp_mem[haveAtLeastOne][current][leftIndex][rightIndex];
double ret = 0.0;
// choose this
{
if(haveAtLeastOne == 0)
{
if(r[current].from < 180.0)
{
ret += r[current].prob * dp(1, current + 1, current, current);
}
}
else
{
if(r[leftIndex].from > r[rightIndex].to)
{
if(r[current].to < r[current].from && r[current].to > r[leftIndex].from)
ret += r[current].prob * 1.0;
else
ret += r[current].prob * dp(1, current + 1, leftIndex, rightIndex);
}
else
{
if(r[current].from < r[rightIndex].to)
{
if(r[current].to < r[current].from)
{
if(r[current].to > r[leftIndex].from)
ret += r[current].prob * 1.0;
else
ret += r[current].prob * dp(1, current + 1, leftIndex, current);
}
else
{
if(r[current].to > r[rightIndex].to)
ret += r[current].prob * dp(1, current + 1, leftIndex, current);
else
ret += r[current].prob * dp(1, current + 1, leftIndex, rightIndex);
}
}
else
{
if(r[current].from < 180.0)
{
ret += r[current].prob * dp(1, current + 1, current, current);
}
}
}
}
}
// not choose this
{
ret += (1 - r[current].prob) * dp(haveAtLeastOne, current + 1, leftIndex, rightIndex);
}
dp_mem[haveAtLeastOne][current][leftIndex][rightIndex] = ret;
done[haveAtLeastOne][current][leftIndex][rightIndex] = true;
return ret;
}
public double totallyCovered(int[] redX, int[] redY, int[] prob, int[] blueX, int[] blueY)
{
int nRed = redX.length;
int nBlue = blueX.length;
for(int i = 0; i < nBlue; i++)
points
[i
] = new Point(blueX
[i
], blueY
[i
]); points = ConvexHull(points);
r = new Range[nRed];
n = 0;
for(int i = 0; i < redX.length; i++)
{
Range t = coverRange(points, p);
if(t.from != t.to)
{
t.prob = prob[i] / 1000.0;
r[n] = t;
n ++;
}
}
for(int iteration = 1; iteration <= n; iteration ++)
for(int i = 0; i < n-1; i++)
if(r[i].from > r[i+1].from)
{
Range t = r[i];
r[i] = r[i+1];
r[i+1] = t;
}
dp_mem = new double[2][n][n][n];
done = new boolean[2][n][n][n];
for(int i = 0; i < 2; i++)
for(int j = 0; j < n; j++)
for(int k = 0; k < n; k++)
for(int l = 0; l < n; l++)
done[i][j][k][l] = false;
return dp(0, 0, 0, 0);
}
}
cHVibGljIGNsYXNzIEJpY2hyb21lU2t5CnsKCWNsYXNzIFBvaW50Cgl7CgkJZG91YmxlIHgsIHk7CgoJCVBvaW50KGRvdWJsZSBfeCwgZG91YmxlIF95KQoJCXsKCQkJeCA9IF94OwoJCQl5ID0gX3k7CgkJfQoKCQlQb2ludCB0byhQb2ludCB0KQoJCXsKCQkJcmV0dXJuIG5ldyBQb2ludCh0LnggLSB4LCB0LnkgLSB5KTsKCQl9CgoJCWRvdWJsZSBjcm9zc1Byb2R1Y3QoUG9pbnQgdCkKCQl7CgkJCXJldHVybiB4ICogdC55IC0geSAqIHQueDsKCQl9CgoJCWRvdWJsZSBkaXJlY3Rpb24oKQoJCXsKCQkJcmV0dXJuIE1hdGguYXRhbjIoeSwgeCk7CgkJfQoJfQoKCWNsYXNzIFJhbmdlCgl7CgkJZG91YmxlIGZyb207CgkJZG91YmxlIHRvOwoJCWRvdWJsZSBwcm9iOwoJfQoKCWRvdWJsZSBmaXgoZG91YmxlIGFuZykKCXsKCQlhbmcgPSBhbmcgKiAxODAgLyBNYXRoLlBJOwoJCXdoaWxlKGFuZyA8IDApIGFuZyArPSAzNjA7CgkJd2hpbGUoYW5nID49IDM2MCkgYW5nIC09IDM2MDsKCQlyZXR1cm4gYW5nOwoJfQoKCVJhbmdlIGNvdmVyUmFuZ2UoUG9pbnRbXSBwb2ludHMsIFBvaW50IHApCgl7CgkJUmFuZ2UgcmV0ID0gbmV3IFJhbmdlKCk7CgkJZm9yKGludCBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykKCQl7CgkJCVBvaW50IGEgPSBwb2ludHNbaV07CgkJCVBvaW50IGIgPSBwb2ludHNbKGkrMSklcG9pbnRzLmxlbmd0aF07CgkJCVBvaW50IGMgPSBwb2ludHNbKGkrMiklcG9pbnRzLmxlbmd0aF07CgkJCWlmKGEudG8oYikuY3Jvc3NQcm9kdWN0KGIudG8ocCkpID4gMCAmJiBiLnRvKHApLmNyb3NzUHJvZHVjdChiLnRvKGMpKSA+IDApCgkJCXsKCQkJCXJldC5mcm9tID0gZml4KGIudG8ocCkuZGlyZWN0aW9uKCkgLSBNYXRoLlBJIC8gMik7CgkJCX0KCgkJCWlmKGEudG8oYikuY3Jvc3NQcm9kdWN0KGIudG8ocCkpIDwgMCAmJiBiLnRvKHApLmNyb3NzUHJvZHVjdChiLnRvKGMpKSA8IDApCgkJCXsKCQkJCXJldC50byA9IGZpeChiLnRvKHApLmRpcmVjdGlvbigpICsgTWF0aC5QSSAvIDIpOwoJCQl9CgkJfQoJCXJldHVybiByZXQ7Cgl9CgoJUG9pbnRbXSBDb252ZXhIdWxsKFBvaW50W10gcG9pbnRzKQoJewoJCWZvcihpbnQgaSA9IDE7IGkgPCBwb2ludHMubGVuZ3RoOyBpKyspCgkJCWlmKHBvaW50c1tpXS55IDwgcG9pbnRzWzBdLnkgfHwgKHBvaW50c1tpXS55ID09IHBvaW50c1swXS55ICYmIHBvaW50c1tpXS54IDwgcG9pbnRzWzBdLngpKQoJCQl7CgkJCQlQb2ludCB0ID0gcG9pbnRzWzBdOwoJCQkJcG9pbnRzWzBdID0gcG9pbnRzW2ldOwoJCQkJcG9pbnRzW2ldID0gdDsKCQkJfQoJCWZvcihpbnQgaXRlcmF0aW9uID0gMTsgaXRlcmF0aW9uIDw9IHBvaW50cy5sZW5ndGg7IGl0ZXJhdGlvbiArKykKCQkJZm9yKGludCBpID0gMTsgaSA8IHBvaW50cy5sZW5ndGgtMTsgaSsrKQoJCQkJaWYocG9pbnRzWzBdLnRvKHBvaW50c1tpXSkuY3Jvc3NQcm9kdWN0KHBvaW50c1swXS50byhwb2ludHNbaSsxXSkpIDwgMCkKCQkJCXsKCQkJCQlQb2ludCB0ID0gcG9pbnRzW2ldOwoJCQkJCXBvaW50c1tpXSA9IHBvaW50c1tpKzFdOwoJCQkJCXBvaW50c1tpKzFdID0gdDsKCQkJCX0KCQlpbnQgeiA9IDI7CgkJZm9yKGludCBpID0gMjsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykKCQl7CgkJCXdoaWxlKHBvaW50c1t6LTJdLnRvKHBvaW50c1t6LTFdKS5jcm9zc1Byb2R1Y3QocG9pbnRzW3otMV0udG8ocG9pbnRzW2ldKSkgPCAwKQoJCQkJeiAtLTsKCQkJcG9pbnRzW3pdID0gcG9pbnRzW2ldOwoJCQl6ICsrOwoJCX0KCQlQb2ludFtdIHJldCA9IG5ldyBQb2ludFt6XTsKCQlmb3IoaW50IGkgPSAwOyBpIDwgejsgaSsrKQoJCQlyZXRbaV0gPSBwb2ludHNbaV07CgkJcmV0dXJuIHJldDsKCX0KCglpbnQgbjsKCVJhbmdlW10gcjsKCWRvdWJsZVtdW11bXVtdIGRwX21lbTsKCWJvb2xlYW5bXVtdW11bXSBkb25lOwoKCWRvdWJsZSBkcChpbnQgaGF2ZUF0TGVhc3RPbmUsIGludCBjdXJyZW50LCBpbnQgbGVmdEluZGV4LCBpbnQgcmlnaHRJbmRleCkKCXsKCQlpZihjdXJyZW50ID09IG4pCgkJCXJldHVybiAwLjA7CgkJaWYoZG9uZVtoYXZlQXRMZWFzdE9uZV1bY3VycmVudF1bbGVmdEluZGV4XVtyaWdodEluZGV4XSkKCQkJcmV0dXJuIGRwX21lbVtoYXZlQXRMZWFzdE9uZV1bY3VycmVudF1bbGVmdEluZGV4XVtyaWdodEluZGV4XTsKCQlkb3VibGUgcmV0ID0gMC4wOwoJCS8vIGNob29zZSB0aGlzCgkJewoJCQlpZihoYXZlQXRMZWFzdE9uZSA9PSAwKQoJCQl7CgkJCQlpZihyW2N1cnJlbnRdLmZyb20gPCAxODAuMCkKCQkJCXsKCQkJCQlyZXQgKz0gcltjdXJyZW50XS5wcm9iICogZHAoMSwgY3VycmVudCArIDEsIGN1cnJlbnQsIGN1cnJlbnQpOwoJCQkJfQoJCQl9CgkJCWVsc2UKCQkJewoJCQkJaWYocltsZWZ0SW5kZXhdLmZyb20gPiByW3JpZ2h0SW5kZXhdLnRvKQoJCQkJewoJCQkJCWlmKHJbY3VycmVudF0udG8gPCByW2N1cnJlbnRdLmZyb20gJiYgcltjdXJyZW50XS50byA+IHJbbGVmdEluZGV4XS5mcm9tKQoJCQkJCQlyZXQgKz0gcltjdXJyZW50XS5wcm9iICogMS4wOwoJCQkJCWVsc2UKCQkJCQkJcmV0ICs9IHJbY3VycmVudF0ucHJvYiAqIGRwKDEsIGN1cnJlbnQgKyAxLCBsZWZ0SW5kZXgsIHJpZ2h0SW5kZXgpOwoJCQkJfQoJCQkJZWxzZQoJCQkJewoJCQkJCWlmKHJbY3VycmVudF0uZnJvbSA8IHJbcmlnaHRJbmRleF0udG8pCgkJCQkJewoJCQkJCQlpZihyW2N1cnJlbnRdLnRvIDwgcltjdXJyZW50XS5mcm9tKQoJCQkJCQl7CgkJCQkJCQlpZihyW2N1cnJlbnRdLnRvID4gcltsZWZ0SW5kZXhdLmZyb20pCgkJCQkJCQkJcmV0ICs9IHJbY3VycmVudF0ucHJvYiAqIDEuMDsKCQkJCQkJCWVsc2UKCQkJCQkJCQlyZXQgKz0gcltjdXJyZW50XS5wcm9iICogZHAoMSwgY3VycmVudCArIDEsIGxlZnRJbmRleCwgY3VycmVudCk7CgkJCQkJCX0KCQkJCQkJZWxzZQoJCQkJCQl7CgkJCQkJCQlpZihyW2N1cnJlbnRdLnRvID4gcltyaWdodEluZGV4XS50bykKCQkJCQkJCQlyZXQgKz0gcltjdXJyZW50XS5wcm9iICogZHAoMSwgY3VycmVudCArIDEsIGxlZnRJbmRleCwgY3VycmVudCk7CgkJCQkJCQllbHNlCgkJCQkJCQkJcmV0ICs9IHJbY3VycmVudF0ucHJvYiAqIGRwKDEsIGN1cnJlbnQgKyAxLCBsZWZ0SW5kZXgsIHJpZ2h0SW5kZXgpOwoJCQkJCQl9CgkJCQkJfQoJCQkJCWVsc2UKCQkJCQl7CgkJCQkJCWlmKHJbY3VycmVudF0uZnJvbSA8IDE4MC4wKQoJCQkJCQl7CgkJCQkJCQlyZXQgKz0gcltjdXJyZW50XS5wcm9iICogZHAoMSwgY3VycmVudCArIDEsIGN1cnJlbnQsIGN1cnJlbnQpOwoJCQkJCQl9CgkJCQkJfQoJCQkJfQoJCQl9CgoJCX0KCQkvLyBub3QgY2hvb3NlIHRoaXMKCQl7CgkJCXJldCArPSAoMSAtIHJbY3VycmVudF0ucHJvYikgKiBkcChoYXZlQXRMZWFzdE9uZSwgY3VycmVudCArIDEsIGxlZnRJbmRleCwgcmlnaHRJbmRleCk7CgkJfQoKCQlkcF9tZW1baGF2ZUF0TGVhc3RPbmVdW2N1cnJlbnRdW2xlZnRJbmRleF1bcmlnaHRJbmRleF0gPSByZXQ7CgkJZG9uZVtoYXZlQXRMZWFzdE9uZV1bY3VycmVudF1bbGVmdEluZGV4XVtyaWdodEluZGV4XSA9IHRydWU7CgkJcmV0dXJuIHJldDsKCX0KCglwdWJsaWMgZG91YmxlIHRvdGFsbHlDb3ZlcmVkKGludFtdIHJlZFgsIGludFtdIHJlZFksIGludFtdIHByb2IsIGludFtdIGJsdWVYLCBpbnRbXSBibHVlWSkKCXsKCQlpbnQgblJlZCA9IHJlZFgubGVuZ3RoOwoJCWludCBuQmx1ZSA9IGJsdWVYLmxlbmd0aDsKCQkKCQlQb2ludFtdIHBvaW50cyA9IG5ldyBQb2ludFtuQmx1ZV07CgkJZm9yKGludCBpID0gMDsgaSA8IG5CbHVlOyBpKyspCgkJCXBvaW50c1tpXSA9IG5ldyBQb2ludChibHVlWFtpXSwgYmx1ZVlbaV0pOwoJCXBvaW50cyA9IENvbnZleEh1bGwocG9pbnRzKTsKCgkJciA9IG5ldyBSYW5nZVtuUmVkXTsKCQluID0gMDsKCQlmb3IoaW50IGkgPSAwOyBpIDwgcmVkWC5sZW5ndGg7IGkrKykKCQl7CgkJCVBvaW50IHAgPSBuZXcgUG9pbnQocmVkWFtpXSwgcmVkWVtpXSk7CgkJCVJhbmdlIHQgPSBjb3ZlclJhbmdlKHBvaW50cywgcCk7CgkJCWlmKHQuZnJvbSAhPSB0LnRvKQoJCQl7CgkJCQl0LnByb2IgPSBwcm9iW2ldIC8gMTAwMC4wOwoJCQkJcltuXSA9IHQ7CgkJCQluICsrOwoJCQl9CgkJfQoKCQlmb3IoaW50IGl0ZXJhdGlvbiA9IDE7IGl0ZXJhdGlvbiA8PSBuOyBpdGVyYXRpb24gKyspCgkJCWZvcihpbnQgaSA9IDA7IGkgPCBuLTE7IGkrKykKCQkJCWlmKHJbaV0uZnJvbSA+IHJbaSsxXS5mcm9tKQoJCQkJewoJCQkJCVJhbmdlIHQgPSByW2ldOwoJCQkJCXJbaV0gPSByW2krMV07CgkJCQkJcltpKzFdID0gdDsKCQkJCX0KCgkJZHBfbWVtID0gbmV3IGRvdWJsZVsyXVtuXVtuXVtuXTsKCQlkb25lID0gbmV3IGJvb2xlYW5bMl1bbl1bbl1bbl07CgkJZm9yKGludCBpID0gMDsgaSA8IDI7IGkrKykKCQkJZm9yKGludCBqID0gMDsgaiA8IG47IGorKykKCQkJCWZvcihpbnQgayA9IDA7IGsgPCBuOyBrKyspCgkJCQkJZm9yKGludCBsID0gMDsgbCA8IG47IGwrKykKCQkJCQkJZG9uZVtpXVtqXVtrXVtsXSA9IGZhbHNlOwoKCQlyZXR1cm4gZHAoMCwgMCwgMCwgMCk7Cgl9Cn0K