[树形dp] Jzoj P5233 概率博弈
生活随笔
收集整理的這篇文章主要介紹了
[树形dp] Jzoj P5233 概率博弈
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Description
小A和小B在玩游戲。這個(gè)游戲是這樣的:有一棵n個(gè)點(diǎn)的以1為根的有根樹,葉子有權(quán)值。假設(shè)有m個(gè)葉子,那么樹上每個(gè)葉子的權(quán)值序列就是一個(gè)1->m 的排列。
一開始在1號(hào)點(diǎn)有一顆棋子。兩人輪流將這顆棋子移向其當(dāng)前位置的一個(gè)兒子。假如棋子到達(dá)葉子,游戲結(jié)束,最終獲得的權(quán)值為所在葉子對(duì)應(yīng)權(quán)值。
小A希望最后的權(quán)值盡量大,小B希望盡量小。小A是先手。
在玩了很多局游戲后,小B對(duì)其中絕大多數(shù)局游戲的結(jié)果不滿意,他覺得是小A對(duì)葉子權(quán)值做了手腳。于是他一怒之下,決定將葉子的權(quán)值隨機(jī)排列。現(xiàn)在小B想知道,假如葉子的權(quán)值是隨機(jī)排列的(即葉子權(quán)值的每種排列都以等概率出現(xiàn)),那么游戲期望的結(jié)果是多少?
請(qǐng)輸出答案乘上m! 對(duì)10^9+7取模的結(jié)果,顯然這是一個(gè)整數(shù)。
Input
輸入文件名為game.in。第一行包含一個(gè)整數(shù)n。
接下來(lái)n-1行,每行兩個(gè)整數(shù)u,v,表示有一條連接節(jié)點(diǎn)u,v的邊。
Output
輸出文件名為game.out。輸出一個(gè)整數(shù),表示答案。
Sample Input
輸入1: 5 1 2 2 3 1 4 2 5輸入2: 10 10 7 7 6 10 2 2 3 3 8 3 1 6 9 7 5 1 4
Sample Output
輸出1: 14輸出2: 74
Data Constraint
對(duì)于10%的數(shù)據(jù),n<=5對(duì)于30%的數(shù)據(jù),n<=10
對(duì)于60%的數(shù)據(jù), n<=50
對(duì)于100%的數(shù)據(jù),n<=5000,保證給出的是一棵合法的樹。
?
題解
- 我們假設(shè)k為最后取的樹,我們把一個(gè)葉子>=k染成1,把<k的染成0
- 考慮一下樹形dp,設(shè)f[i][j][0/1]為以i為根的子樹中有j個(gè)1當(dāng)前點(diǎn)為0/1的方案數(shù)
- 那么對(duì)于當(dāng)前是基層,也就是小A取值,f[i][j][0]= ∏f[son[x]][k][0],f[i][j][1]=。對(duì)于偶層,也就是小B取值也是一樣的
- 枚舉前面兒子的葉子然后枚舉當(dāng)前要合并的兒子的葉子背包一下
- 我們可以枚舉k,也就是子樹中1的個(gè)數(shù),所以我們最后要記入答案是∑(f[1][k][1]-f[1][k+1][1])k!?(size[1]-k)!
代碼
1 #include <cstdio> 2 #define ll long long 3 using namespace std; 4 const ll N=5010,mo=1e9+7; 5 struct edge { int to,from; }e[N*2]; 6 ll f[N][N][2],head[N],size[N],jc[N],g[N],ans,n,cnt,r; 7 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; } 8 ll ksm(ll a,ll b){ for (r=1;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r;} 9 ll C(ll x,ll y) { return jc[y]*ksm(jc[y-x],mo-2)%mo*ksm(jc[x],mo-2)%mo; } 10 void dfs(int d,int x,int y,int l,int r) 11 { 12 if (d>g[0]) { (f[x][r][l]+=y)%=mo; return; } 13 for (int i=0;i<=size[g[d]];i++) if (f[g[d]][i][l]) dfs(d+1,x,y*f[g[d]][i][l]%mo,l,r+i); 14 } 15 void dp(int x,int y,int k) 16 { 17 for (int i=head[x];i;i=e[i].from) if (e[i].to!=y) dp(e[i].to,x,k^1),size[x]+=size[e[i].to]; 18 g[0]=0; for (int i=head[x];i;i=e[i].from) if (e[i].to!=y) g[++g[0]]=e[i].to; 19 if (size[x]) 20 { 21 dfs(1,x,1,k,0); 22 for (int i=0;i<=size[x];i++) f[x][i][k^1]=(C(i,size[x])-f[x][i][k]+mo)%mo; 23 } 24 else size[x]++,f[x][0][0]=f[x][1][1]=1; 25 } 26 int main() 27 { 28 freopen("game.in","r",stdin),freopen("game.out","w",stdout),scanf("%lld",&n); 29 for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x); 30 jc[0]=1; for (int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mo; dp(1,0,0); 31 for (int i=0;i<=size[1];i++) (ans+=f[1][i][1]*jc[i]%mo*jc[size[1]-i]%mo)%=mo; 32 printf("%lld",ans); 33 }
?
轉(zhuǎn)載于:https://www.cnblogs.com/Comfortable/p/10296073.html
總結(jié)
以上是生活随笔為你收集整理的[树形dp] Jzoj P5233 概率博弈的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 网吧多少钱一小时啊?
- 下一篇: P2261 [CQOI2007]余数求和