Solution -「AGC 020F」Arcs on a Circle


\(\mathscr{Description}\)

??Link.

??在一个周长为 \(c\) 的圆周上放置长度分别为 \(l_1,l_2,\cdots,l_n\) 的弧,每条弧的位置独立均匀随机。求圆周被弧的并完全覆盖的概率。

??\(n\le6\)\(c\le50\),输入均为整数。

\(\mathscr{Solution}\)

??记一个几乎没见过的 trick。顺便,真就 \(n\) 越小题越难呗。

??不妨设 \(l_1\le\cdots\le l_n\),首先取 \(l_n\) 的左端点为坐标 \(0\) 点,将圆弧展开成数轴,如此可以避免“某条弧跨过 \(0\) 点向后覆盖”的情况。由于 \(l_i\) 为整数,所以所有 \(l\) 的端点坐标一定可以表示为 \(k+\epsilon\),其中 \(\epsilon\in S\subseteq[0,1)\),且 \(|S|\le n\)。忽略次要矛盾,\(|S|=n\)。直接枚举 \(l_{1..n-1}\) 的左端点 \(\epsilon\) 大小关系,就把问题转化到离散情况。状压 DP 一下即可。复杂度 \(\mathcal O(n!2^nn^2c^2)\)

\(\mathscr{Code}\)

/*+Rainybunny+*/

#include 

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)

const int MAXN = 6, MAXC = 50;
int n, c, prm[MAXN + 5], l[MAXN];
double f[MAXN * MAXC + 5][1 << MAXN >> 1];

int main() {
    scanf("%d %d", &n, &c);
    rep (i, 0, n - 1) scanf("%d", &l[i]);
    std::sort(l, l + n);

    double ans = 0.; int all = 0;
    rep (i, 0, n - 2) prm[i] = i;
    do {
        memset(f, 0, sizeof f);
        f[l[n - 1] * n][0] = 1;
        rep (i, 1, n * c) if (i % n) {
            int r = i % n - 1;
            rep (j, i, n * c) {
                rep (S, 0, (1 << n >> 1) - 1) if (~S >> r & 1) {
                    f[std::min(c * n, std::max(j, i + l[prm[r]] * n))]
                    [S | 1 << r] += f[j][S];
                }
            }
        }
        ans += f[c * n][(1 << n >> 1) - 1], ++all;
    } while (std::next_permutation(prm, prm + n - 1));
    printf("%.12f\n", ans / all / pow(c, n - 1));
    return 0;
}

相关