bzoj 5004 開鎖魔法II

2021-08-13 17:17:33 字數 1939 閱讀 9202

給你n個點,每個點有且只有一條有向邊邊

你可以在上面選擇k個點,問你選到這k個點,沿著邊走,可以走完整個圖的概率是多少

很明顯,這個圖,最後會成為很多個不同的聯通塊

然後對於每乙個聯通塊,我們縮點之後,就會出現乙個樹,明顯地,樹的根是一定要選的

當然,樹的根有可能是乙個環

然而環裡面,你任意選擇乙個,就可以將環遍歷完了

所以,我們可以考慮用

i 個節點,把每乙個根都選到,有多少種方案,然後剩下的(k

−i)個節點,在別的點裡面排列組合就好了。。

於是問題就轉變成了,現在給你i個選擇機會,有n個盒子,每個盒子裡面有ai

個球,問你每個盒子至少選擇乙個球,有多少種方案

這個的話,怒想了一波排列組合無果

於是就只好用dp了 f[

i][j

] 表示,前i個盒子,選了j個球,都合法了,有多少種情況

轉移也很容易,我就不再贅述了

然後就做完了。。

dp完之後,在列舉一下沒多少給根,然後排列組合乘一下就可以了

打到一半,我才發現,會炸精度。。

於是有想了半天。。

於是好奇題解有沒有排列組合。。

發現他居然直接用double來存。。

smg,300的排列組合居然不怕炸精度?

於是我也試了一下,居然就過了qaq

看來還是我太年輕了啊

code:

#include

#include

#include

#include

#include

using

namespace

std;

const

int n=305;

int t;

struct qq

e[n];

int num,last[n];

int n,k;

void init (int x,int y)

int dfn[n],low[n],sta[n],belong[n],tt[n];

bool in[n];

int lalal,cnt,shen;

void dfs (int x)

else

if (in[y]) low[x]=min(dfn[y],low[x]);

}if (dfn[x]==low[x])

while (now!=x);

}}int d[n];

int a[n],tot;//這些必選的盒子裡面,有多少個人

int sum;//剩下的有多少個

double f[n][n];//前i個盒子 選了j個,有多少種方案

double c[n][n];

void solve ()

double ans=0;

for (int u=1;u<=k;u++)//給他多少

ans=ans+f[tot][u]*c[sum][k-u];

printf("%.9lf\n",ans/c[n][k]);

}int main()

while (t--)

lalal=0;cnt=0;shen=0;

memset(dfn,-1,sizeof(dfn));

memset(in,false,sizeof(in));

for (int u=1;u<=n;u++)

if (dfn[u]==-1)

dfs(u);

memset(d,0,sizeof(d));

for (int u=1;u<=num;u++)

tot=0;

sum=n;

for (int u=1;u<=shen;u++)

if (d[u]==0)

solve();

}return

0;}

bzoj5004 開鎖魔法II dp

一日,崔克茜來到小馬鎮表演魔法。其中乙個節目是開鎖咒 舞台上有n 個盒子,每個盒子中有一把鑰匙,對於每個盒子而言有且僅有一把鑰匙能開啟它。初始時,崔克茜將會隨機地選擇k個盒子用魔法將它們開啟。崔克茜想知道最後 所有盒子都被開啟的概率,你能幫助她回答這個問題嗎?考慮鑰匙向盒子連邊,形成的圖一定為多個不...

BZOJ 5004 開鎖魔法II 概率dp

盒子之間的開啟關係 用圖的方式呈現 就是一片環 最終所有成功開啟 則每一顆環都成功開啟 所以求出每個環放k個點成功的概率 之後依次列舉每一顆環 及其內部選擇點數與在之前的環中選擇點數 再乘上對應概率 include include include include include include in...

bzoj3038(線段樹開根)

法1,因為最多不會開根6次,所以開根,直接搞 include include include include includeusing namespace std typedef long long ll inline ll read int n struct aa a 100025 4 void ...