Atcoder AGC020 F - Arcs on a Circle

链接:

link

题意:

有一个长度为 C 的环,有N个圆弧,长度为 Li ,将它们任意放置,求所有位置都被至少一个圆弧覆盖的概率。

题解:

为了方便,取 L 最大的圆弧的放置位置的左端点作为原点。

记其他圆弧的放置位置为Xi=Pi+Fi,其中 Pi=Xi ,可以认为 Pi [0,C) 均匀随机的一个整数,而 Fi [0,1) 均匀随机的一个实数。

Fi 的值并不重要,事实上只需要考虑他们的大小关系,所以可以 (N1)! 地枚举所有大小关系(它们出现概率都相等),接下来就可以DP了:一共有 N×C 个不同的出现位置, f(i,j,k) 表示考虑前 i 个出现位置,当前放的圆弧状态为j,覆盖的最远位置为 k <script type="math/tex" id="MathJax-Element-712">k</script>的方案数。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 305;

int n, m, a[N], per[N];
LL sum, cnt, f[N][35];

inline LL Solve() {
  for (int i = 0; i <= n * m; ++i) {
    for (int j = 0; j < 1 << n - 1; ++j) {
      f[i][j] = 0;
    }
  }
  f[n * a[n - 1]][0] = 1;
  for (int i = 0; i < n * m; ++i) {
    for (int j = i; j <= n * m; ++j) {
      for (int k = 0; k < 1 << n - 1; ++k) {
        if (i % n && !(k >> per[i % n - 1] & 1)) {
          f[min(n * m, max(j, i + n * a[per[i % n - 1]]))][k | 1 << per[i % n - 1]] += f[j][k];
        }
      }
    }
  }
  return f[n * m][(1 << n - 1) - 1];
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 0; i < n; ++i) {
    Read(a[i]);
  }
  sort(a, a + n);
  for (int i = 0; i < n - 1; ++i) {
    per[i] = i;
  }
  do {
    sum += Solve();
    ++cnt;
  } while (next_permutation(per, per + n - 1));
  for (int i = 0; i < n - 1; ++i) {
    cnt = cnt * m;
  }
  printf("%.12lf\n", (double)sum / cnt);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值