[DP 组合] BZOJ5004 & Hihocoder1075. 开锁魔法 III

i ai 连边,会形成若干个环

那么把钥匙分配给这些环的概率就是答案

DP

fi,j 表示前 i 个环都打开了,还剩下 j 把钥匙的概率

fi,j=fi1,k×(sizeikj)(nsizeij)(nk)

这样DP是 O(n2)

不过BZOJ没有spj,被卡精度了…hihocoder上过了…

DP转移可以改一下

fi,j=fi1,k×(sizeikj)

这样求出总方案数,最后除以 (nk) 就好了…

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N=310;

int T,t,n,k,size[N],vis[N],a[N];
double f[N][N],C[N][N];

int dfs(int x){
  if(vis[x]) return 0;
  vis[x]=1; return dfs(a[x])+1;
}

int main(){
  scanf("%d",&T);
  C[1][1]=1; C[0][0]=1;
  for(int i=1;i<=300;i++) C[i][0]=1;
  for(int i=2;i<=300;i++)
    for(int j=1;j<=i;j++)
      C[i][j]=C[i-1][j]+C[i-1][j-1];
  while(T--){
    scanf("%d%d",&n,&k); int nn=n;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) vis[i]=size[i]=0;
    t=0;
    for(int i=1;i<=n;i++){
      if(vis[i]) continue;
      t++; size[t]=dfs(i);
    }
    for(int i=0;i<=n;i++)
      for(int j=0;j<=k;j++) f[i][j]=0;
    f[0][k]=1;
    for(int i=1;i<=t;i++){
      for(int j=1;j<=k;j++){
    if(f[i-1][j]<1e-7) continue;
    for(int s=1;s<=size[i] && s<=j;s++)
      f[i][j-s]+=f[i-1][j]*C[size[i]][s];
      }
      n-=size[i];
    }
    printf("%.9lf\n",f[t][0]/C[nn][k]);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值