import java.io.OutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Arrays; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.io.Writer; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.InputStream; /** * Built using CHelper plug-in * Actual solution is at the top * * @author lewin */ public class cookie_cutter_lewin { public static void main(String[] args) { InputStream inputStream = System.in; OutputStream outputStream = System.out; InputReader2 in = new InputReader2(inputStream); OutputWriter out = new OutputWriter(outputStream); CookieCutter solver = new CookieCutter(); solver.solve(1, in, out); out.close(); } static class CookieCutter { int len; int n; int[] x; int[] y; public void solve(int testNumber, InputReader2 in, OutputWriter out) { len = in.nextInt(); n = in.nextInt(); x = new int[n]; y = new int[n]; for (int i = 0; i < n; i++) { x[i] = in.nextInt(); y[i] = in.nextInt(); } double best = 0; // try single chip solutions for (int k = 0; k < 4; k++) { // assume bottom left corner, rotate 4 times for (int i = 0; i < n; i++) { if (x[i] + x[i] <= len && y[i] + y[i] <= len) { // this line goes through (0, 2y) and (2x, 0) int above = 0, equal = 0, below = 0; for (int j = 0; j < n; j++) { int diff = x[j] * y[i] + x[i] * y[j] - 2 * x[i] * y[i]; if (diff > 0) above++; else if (diff == 0) equal++; else below++; } double area_below = 2.0 * x[i] * y[i] / len / len, area_above = 1.0 - area_below; best = Math.max(best, (below + equal) * 1.0 / n - area_below); best = Math.max(best, (above + equal) * 1.0 / n - area_above); } } for (int i = 0; i < n; i++) { int t = x[i]; x[i] = y[i]; y[i] = len - t; } } LineGeometry.Point[] poly = new LineGeometry.Point[4]; poly[0] = new LineGeometry.Point(0, 0); poly[1] = new LineGeometry.Point(0, len); poly[2] = new LineGeometry.Point(len, len); poly[3] = new LineGeometry.Point(len, 0); // try two chip solutions for (int center = 0; center < n; center++) { AngleAreaOrientationSortRotationPerpendicular.Point[] pts = new AngleAreaOrientationSortRotationPerpendicular.Point[2 * (n - 1)]; int idx = 0; for (int i = 0; i < n; i++) { if (i == center) continue; pts[idx++] = new AngleAreaOrientationSortRotationPerpendicular.Point(x[i] - x[center], y[i] - y[center], i); } Arrays.sort(pts, 0, n - 1); for (int i = 0; i < n - 1; i++) { pts[i + n - 1] = pts[i]; } int front = 0; for (int i = 0; i < n - 1; i++) { while (front < i + n - 1 && pts[i].x * pts[front].y - pts[i].y * pts[front].x >= 0) { front++; } double area = LineGeometry.signedArea(LineGeometry.convexCut( poly, new LineGeometry.Point(x[center], y[center]), new LineGeometry.Point(x[pts[i].id], y[pts[i].id]))); best = Math.max(best, (front - i + 1) * 1.0 / n - area / len / len); while (i < n - 1 && pts[i].x * pts[i + 1].y - pts[i].y * pts[i + 1].x == 0 && (pts[i].x > 0 == pts[i + 1].x > 0)) i++; } } out.printf("%.10f\n", best); } } static class AngleAreaOrientationSortRotationPerpendicular { public static class Point implements Comparable { public int x; public int y; public int id; public Point(int x, int y, int id) { this.x = x; this.y = y; this.id = id; } public Point(int x, int y) { this.x = x; this.y = y; } public int compareTo(AngleAreaOrientationSortRotationPerpendicular.Point o) { boolean up1 = y > 0 || (y == 0 && x >= 0); boolean up2 = o.y > 0 || (o.y == 0 && o.x >= 0); if (up1 != up2) return up1 ? -1 : 1; int cmp = Long.signum((long) o.x * y - (long) o.y * x); if (cmp != 0) return cmp; return Long.compare((long) x * x + (long) y * y, (long) o.x * o.x + (long) o.y * o.y); //return Double.compare(Math.atan2(y, x), Math.atan2(o.y, o.x)); } public String toString() { return "(" + x + ',' + y + ')'; } } } static class LineGeometry { static final double EPS = 1e-10; public static int sign(double a) { return a < -EPS ? -1 : a > EPS ? 1 : 0; } public static int orientation(LineGeometry.Point a, LineGeometry.Point b, LineGeometry.Point c) { LineGeometry.Point AB = b.minus(a); LineGeometry.Point AC = c.minus(a); return sign(AB.cross(AC)); } public static double signedArea(LineGeometry.Point[] points) { int n = points.length; double area = 0; for (int i = 0, j = n - 1; i < n; j = i++) { area += (points[i].x - points[j].x) * (points[i].y + points[j].y); // area += points[i].x * points[j].y - points[j].x * points[i].y; } return area / 2; } public static LineGeometry.Point[] convexCut(LineGeometry.Point[] poly, LineGeometry.Point p1, LineGeometry.Point p2) { int n = poly.length; List res = new ArrayList<>(); for (int i = 0, j = n - 1; i < n; j = i++) { int d1 = orientation(p1, p2, poly[j]); int d2 = orientation(p1, p2, poly[i]); if (d1 >= 0) res.add(poly[j]); if (d1 * d2 < 0) res.add(new LineGeometry.Line(p1, p2).intersect(new LineGeometry.Line(poly[j], poly[i]))); } return res.toArray(new LineGeometry.Point[res.size()]); } public static class Point implements Comparable { public double x; public double y; public Point(double x, double y) { this.x = x; this.y = y; } public LineGeometry.Point minus(LineGeometry.Point b) { return new LineGeometry.Point(x - b.x, y - b.y); } public double cross(LineGeometry.Point b) { return x * b.y - y * b.x; } public int compareTo(LineGeometry.Point o) { // return Double.compare(Math.atan2(y, x), Math.atan2(o.y, o.x)); return Double.compare(x, o.x) != 0 ? Double.compare(x, o.x) : Double.compare(y, o.y); } } public static class Line { public double a; public double b; public double c; public Line(double a, double b, double c) { this.a = a; this.b = b; this.c = c; } public Line(LineGeometry.Point p1, LineGeometry.Point p2) { a = +(p1.y - p2.y); b = -(p1.x - p2.x); c = p1.x * p2.y - p2.x * p1.y; } public LineGeometry.Point intersect(LineGeometry.Line line) { double d = a * line.b - line.a * b; if (sign(d) == 0) { return null; } double x = -(c * line.b - line.c * b) / d; double y = -(a * line.c - line.a * c) / d; return new LineGeometry.Point(x, y); } } } static class InputReader2 { private BufferedReader in; private StringTokenizer st; public InputReader2(InputStream stream) { in = new BufferedReader(new InputStreamReader(stream)); st = null; } public int nextInt() { return Integer.parseInt(next()); } public String next() { while (st == null || !st.hasMoreTokens()) { try { st = new StringTokenizer(in.readLine()); } catch (IOException e) { e.printStackTrace(); } } return st.nextToken(); } } static class OutputWriter { private final PrintWriter writer; public OutputWriter(OutputStream outputStream) { writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream))); } public OutputWriter(Writer writer) { this.writer = new PrintWriter(writer); } public void printf(String format, Object... objects) { writer.printf(format, objects); } public void close() { writer.close(); } } }