public class Euler547 {

    static void legendrePolyAndDeriv(int n, double x, double[] out) {
        double pnm1 = 1.0;
        double pnLocal = x;
        if (n == 0) {
            out[0] = 1.0;
            out[1] = 0.0;
            return;
        }
        if (n == 1) {
            out[0] = x;
            out[1] = 1.0;
            return;
        }

        for (int k = 2; k <= n; k++) {
            double pk = ((2.0 * k - 1.0) * x * pnLocal - (k - 1.0) * pnm1) / k;
            pnm1 = pnLocal;
            pnLocal = pk;
        }

        out[0] = pnLocal;
        out[1] = n * (x * pnLocal - pnm1) / (x * x - 1.0);
    }

    static void buildGaussLegendre(int order, double[] nodes, double[] weights) {
        int half = (order + 1) / 2;
        double pi = Math.PI;

        double[] out = new double[2];
        for (int i = 0; i < half; i++) {
            double z = Math.cos(pi * (i + 0.75) / (order + 0.5));
            for (int iter = 0; iter < 80; iter++) {
                legendrePolyAndDeriv(order, z, out);
                double pn = out[0], dpn = out[1];
                double dz = pn / dpn;
                z -= dz;
                if (Math.abs(dz) < 1e-15) {
                    break;
                }
            }

            legendrePolyAndDeriv(order, z, out);
            double pn = out[0], dpn = out[1];
            double w = 2.0 / ((1.0 - z * z) * dpn * dpn);

            int j = order - 1 - i;
            nodes[i] = (1.0 - z) * 0.5;
            nodes[j] = (1.0 + z) * 0.5;
            weights[i] = w * 0.5;
            weights[j] = w * 0.5;
        }
    }

    static double[][] buildKernelTable(int maxN, int qOrder) {
        int maxDiff = maxN - 1;
        double[][] kernel = new double[maxDiff + 1][maxDiff + 1];

        double[] nodes = new double[qOrder];
        double[] weights = new double[qOrder];
        buildGaussLegendre(qOrder, nodes, weights);

        for (int dx = 0; dx <= maxDiff; dx++) {
            for (int dy = 0; dy <= maxDiff; dy++) {
                double s = 0.0;
                for (int i = 0; i < qOrder; i++) {
                    double u = nodes[i];
                    double wu = weights[i];
                    double ux = 1.0 - u;
                    for (int j = 0; j < qOrder; j++) {
                        double v = nodes[j];
                        double wv = weights[j];
                        double vy = 1.0 - v;

                        double p1 = Math.hypot(dx + u, dy + v);
                        double p2 = Math.hypot(dx + u, dy - v);
                        double p3 = Math.hypot(dx - u, dy + v);
                        double p4 = Math.hypot(dx - u, dy - v);
                        s += wu * wv * ux * vy * (p1 + p2 + p3 + p4);
                    }
                }
                kernel[dx][dy] = s;
            }
        }
        return kernel;
    }

    static double[][] buildRectSelfTable(int maxN, double[][] kernel) {
        double[][] self = new double[maxN + 1][maxN + 1];
        for (int w = 1; w <= maxN; w++) {
            for (int h = 1; h <= maxN; h++) {
                double s = 0.0;
                for (int dx = -(w - 1); dx <= w - 1; dx++) {
                    double cx = w - Math.abs(dx);
                    for (int dy = -(h - 1); dy <= h - 1; dy++) {
                        double cy = h - Math.abs(dy);
                        s += cx * cy * kernel[Math.abs(dx)][Math.abs(dy)];
                    }
                }
                self[w][h] = s;
            }
        }
        return self;
    }

    static double[][] buildOuterPrefix(int n, double[][] kernel) {
        double[][] w = new double[n][n];
        for (int hx = 0; hx < n; hx++) {
            for (int hy = 0; hy < n; hy++) {
                double s = 0.0;
                for (int ox = 0; ox < n; ox++) {
                    for (int oy = 0; oy < n; oy++) {
                        s += kernel[Math.abs(ox - hx)][Math.abs(oy - hy)];
                    }
                }
                w[hx][hy] = s;
            }
        }

        double[][] prefix = new double[n + 1][n + 1];
        for (int x = 0; x < n; x++) {
            double rowAcc = 0.0;
            for (int y = 0; y < n; y++) {
                rowAcc += w[x][y];
                prefix[x + 1][y + 1] = prefix[x][y + 1] + rowAcc;
            }
        }
        return prefix;
    }

    static double computeSForN(int n, double[][] kernel, double[][] rectSelf) {
        if (n < 3)
            return 0.0;
        double[][] prefix = buildOuterPrefix(n, kernel);
        double fOuterOuter = rectSelf[n][n];

        double total = 0.0;
        for (int x = 1; x <= n - 2; x++) {
            for (int y = 1; y <= n - 2; y++) {
                double fHoleHole = rectSelf[x][y];
                double areaRing = (double) n * n - (double) x * y;
                double invAreaSq = 1.0 / (areaRing * areaRing);

                double localSum = 0.0;
                for (int a = 1; a <= n - x - 1; a++) {
                    for (int b = 1; b <= n - y - 1; b++) {
                        double fOuterHole = prefix[a + x][b + y] - prefix[a][b + y] - prefix[a + x][b] + prefix[a][b];
                        double fRingRing = fOuterOuter - 2.0 * fOuterHole + fHoleHole;
                        localSum += fRingRing * invAreaSq;
                    }
                }
                total += localSum;
            }
        }
        return total;
    }

    public static String solve() {
        int n = 40;
        int qOrder = 64;
        double[][] kernel = buildKernelTable(n, qOrder);
        double[][] rectSelf = buildRectSelfTable(n, kernel);
        double ans = computeSForN(n, kernel, rectSelf);
        return String.format(java.util.Locale.US, "%.4f", ans);
    }

    public static void main(String[] args) {
        System.out.println(solve());
    }
}
