【YBT2022寒假Day7 C】【luogu CF603E】以线覆圆 / Arcs on a Circle(期望)(DP)

以线覆圆 / Arcs on a Circle

题目链接:YBT2022寒假Day7 C / luogu AT3860

题目大意

给你一个周长为 n 的圆和一些长度的线段。
然后每条线段会随机出现在圆中,然后问你这些线段把整个圆覆盖的期望。

思路

我们首先考虑如果线段端点只能是整数,那我们不难有个方法:断环为链来 DP。(然后为了保证不重,我们保证第一个线段用的一定是最长的,并从这里开始)
然后如果我们不断提高他的精度,那这个 DP 就是对的。

然后你会发现它这个 DP 好像没有必要这个精度,好像我们只要确定这些点之间的相对关系即可。
(而且因为是实数,所以是可以认为两个点在同一位置的概率为 0 0 0

然后我们可以把它变成 n ∗ c n*c nc 个点,我们考虑 DP:
首先我们要确定这些线段在小数部分的相对关系,所以要用 n ! n! n! 搞个全排列。

f i , j , k f_{i,j,k} fi,j,k 为看到第 i i i 个点,然后已经覆盖到了 j j j 点,线段用的状态时 k k k
然后我们就考虑当前点对应的线段在不在这里用,转移是 O ( 1 ) O(1) O(1) 的。

然后就可以了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int c, n, l[7], xl[7], t;
double ans, f[301][32];

double ksm(double x, int y) {
	double re = 1;
	while (y) {
		if (y & 1) re = re * x;
		x = x * x;
		y >>= 1;
	}
	return re;
}

int main() {
//	freopen("circle.in", "r", stdin);
//	freopen("circle.out", "w", stdout);
	
	scanf("%d %d", &n, &c); t = 1;
	for (int i = 1; i <= n; i++) {
		xl[i] = i; t = t * i;
		scanf("%d", &l[i]);
	}
	sort(l + 1, l + n + 1);
	
	for (int qq = 1; qq <= t; qq++) {
		memset(f, 0, sizeof(f));
		
		f[l[n] * n][0] = 1;
		for (int i = 1; i <= n * c; i++) {
			if (i % n == 0) continue; int pl = i % n;
			for (int j = i; j <= n * c; j++)
				for (int k = 0; k < (1 << (n - 1)); k++) {
					if ((k >> (pl - 1)) & 1) continue;
					f[min(n * c, max(j, i + l[xl[pl]] * n))][k | (1 << (pl - 1))] += f[j][k];
				}
		}
		ans += f[n * c][(1 << (n - 1)) - 1];
		
		next_permutation(xl + 1, xl + n);
	}
	
	printf("%.16lf", ans / ksm(c, n - 1) / t);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值