【bzoj5004】开锁魔法II 组合数学+概率dp

题目描述

n 个箱子,每个箱子里有且仅有一把钥匙,每个箱子有且仅有一把钥匙可以将其打开。现在随机打开 m 个箱子,求能够将所有箱子打开的概率。


题解

组合数学+概率dp

题目约定了每个点的入度和出度均为1,因此最终的图一定是若干个环。每个环都至少选择一个点即可满足要求。

预处理出每个环的点数 c[i] 以及其后缀和 sum[i]

f[i][j] 表示前 i 个环中选出 j 个点,满足最终条件的概率。初始化 f[0][0]=1

枚举 i 和前 i1 个环的点数 j 、第 i 个环的点数 k ,那么:in 的总方案数为 Csum[i]mj ,满足条件的方案数为 c[i] 中选出 k 个的方案数乘以剩下部分选出 mjk 个的方案数 Cc[i]k·Csum[i]c[i]mjk

整理一下即可得到dp方程 f[i][j+k]f[i1][j]·Cc[i]k·Csum[i]c[i]mjkCsum[i]mj

最后的答案就是 f[n][m]

其中组合数直接使用double存据说能过,然而我比较怂,因此存的是阶乘的 ln ,求的时候再 exp 回去。

时间复杂度 O(Tn2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 310
using namespace std;
int a[N] , c[N] , vis[N] , sum[N];
double fac[N] , f[N][N];
int main()
{
    int T;
    scanf("%d" , &T);
    while(T -- )
    {
        memset(vis , 0 , sizeof(vis));
        memset(f , 0 , sizeof(f));
        f[0][0] = 1;
        int n , m = 0 , p , i , j , k;
        scanf("%d%d" , &n , &p);
        for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , fac[i] = fac[i - 1] + log(i);
        for(i = 1 ; i <= n ; i ++ )
        {
            if(!vis[i])
            {
                c[++m] = 0;
                for(j = i ; !vis[j] ; j = a[j])
                    vis[j] = 1 , c[m] ++ ;
            }
        }
        sum[m + 1] = 0;
        for(i = m ; i ; i -- ) sum[i] = sum[i + 1] + c[i];
        for(i = 1 ; i <= m ; i ++ )
            for(j = max(i - 1 , p - sum[i]) ; j < p && j <= n - sum[i] ; j ++ )
                for(k = 1 ; k <= c[i] && j + k <= p ; k ++ )
                    f[i][j + k] += f[i - 1][j] * exp(fac[c[i]] + fac[sum[i] - c[i]] + fac[p - j] + fac[sum[i] - p + j] - fac[k] - fac[c[i] - k] - fac[p - j - k] - fac[sum[i] - c[i] - p + j + k] - fac[sum[i]]);
        printf("%.9lf\n" , f[m][p]);
    }
    return 0;
}

 

posted @   GXZlegend  阅读(1985)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2017-04-05 【bzoj1263】[SCOI2006]整数划分 高精度
2017-04-05 【bzoj4551】[Tjoi2016&Heoi2016]树 并查集
2017-04-05 【bzoj4517】[Sdoi2016]排列计数 组合数+dp
点击右上角即可分享
微信分享提示