• AT3860[AGC020F]Arcs on a Circle【dp】


    正题

    题目链接:https://www.luogu.com.cn/problem/AT3860


    题目大意

    有一个周长为\(m\)的圆,\(n\)条线段,第\(i\)条长度为\(a_i\),将线段贴在圆的随机位置上,求整个圆都被覆盖的概率。

    \(1\leq n\leq 6,1\leq m\le 50\)


    解题思路

    这种随机实数的问题我们可以从排名方面考虑。

    先固定最长的一条线不动且左端点作为起点就可以不需要考虑环的问题了,然后对于每条线的开头离上一个整点的距离\(d\)进行一个排序,就可以作为每条线的排名了。

    具体地,我们枚举一个排列作为排名,那这样就变为了\(n\times m\)个点(每个排名),考虑用\(dp\)解决问题。

    首先我们需要记录线段的使用状态,然后我们一个一个位置考虑线段是否填,然后还需要目前延伸到的最末尾位置。

    \(f_{l,r,s}\)表示目前填到\(l\),最远延伸到\(r\),线段使用状态为\(s\)时的概率,然后因为我们线段开头的排名是确定的,所以对于一个\(l\)只能有一条线段可以填,可以省去枚举这条线段的时间。

    时间复杂度:\(O(n^2m^22^nn!)\)

    实际上常数很小,可以通过本题


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const double eps=1e-9;
    int n,m,cnt,a[10];
    double ans,f[500][70];
    int main()
    {
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<n;i++)
    		scanf("%d",&a[i]),a[i]=a[i]*n;
    	sort(a,a+n);
    	do{
    		int MS=(1<<n-1);
    		for(int i=0;i<=n*m;i++)
    			for(int s=0;s<MS;s++)
    				f[i][s]=0;
    		f[a[n-1]][0]=1;
    		for(int i=1;i<=n*m;i++){
    			if(i%n==0)continue;int x=i%n-1;
    			for(int j=i;j<=n*m;j++){
      				for(int s=0;s<MS;s++){
    					if(f[j][s]<eps||((s>>x)&1))continue;
    					f[min(n*m,max(j,i+a[x]))][s|(1<<x)]+=f[j][s];
    				}
    			}
    		}
    		ans+=f[n*m][MS-1];cnt++;
    	}while(next_permutation(a,a+n-1));
    	printf("%.12lf",ans/(double)cnt/pow(m,n-1));
    	return 0;
    }
    
  • 相关阅读:
    uva 12034 Race
    计算机基础之计算机硬件软件数据结构
    Project Perfect让Swift在server端跑起来-Perfect in Visual Studio Code (四)
    关于自己定义转场动画,我都告诉你。
    Shell编程入门
    CODEVS 1029 遍历问题
    【VBA研究】工作表自己主动筛选模式检測
    卸载MySQL 5.0
    操作系统(二)进程控制
    前端面试题
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15884040.html
Copyright © 2020-2023  润新知