[树形dp] Jzoj P5233 概率博弈
生活随笔
收集整理的這篇文章主要介紹了
[树形dp] Jzoj P5233 概率博弈
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
小A和小B在玩游戲。這個游戲是這樣的:有一棵n個點的以1為根的有根樹,葉子有權值。假設有m個葉子,那么樹上每個葉子的權值序列就是一個1->m 的排列。
一開始在1號點有一顆棋子。兩人輪流將這顆棋子移向其當前位置的一個兒子。假如棋子到達葉子,游戲結束,最終獲得的權值為所在葉子對應權值。
小A希望最后的權值盡量大,小B希望盡量小。小A是先手。
在玩了很多局游戲后,小B對其中絕大多數局游戲的結果不滿意,他覺得是小A對葉子權值做了手腳。于是他一怒之下,決定將葉子的權值隨機排列。現在小B想知道,假如葉子的權值是隨機排列的(即葉子權值的每種排列都以等概率出現),那么游戲期望的結果是多少?
請輸出答案乘上m! 對10^9+7取模的結果,顯然這是一個整數。
Input
輸入文件名為game.in。第一行包含一個整數n。
接下來n-1行,每行兩個整數u,v,表示有一條連接節點u,v的邊。
Output
輸出文件名為game.out。輸出一個整數,表示答案。
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
對于10%的數據,n<=5對于30%的數據,n<=10
對于60%的數據, n<=50
對于100%的數據,n<=5000,保證給出的是一棵合法的樹。
?
題解
- 我們假設k為最后取的樹,我們把一個葉子>=k染成1,把<k的染成0
- 考慮一下樹形dp,設f[i][j][0/1]為以i為根的子樹中有j個1當前點為0/1的方案數
- 那么對于當前是基層,也就是小A取值,f[i][j][0]= ∏f[son[x]][k][0],f[i][j][1]=。對于偶層,也就是小B取值也是一樣的
- 枚舉前面兒子的葉子然后枚舉當前要合并的兒子的葉子背包一下
- 我們可以枚舉k,也就是子樹中1的個數,所以我們最后要記入答案是∑(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 }
?
轉載于:https://www.cnblogs.com/Comfortable/p/10296073.html
總結
以上是生活随笔為你收集整理的[树形dp] Jzoj P5233 概率博弈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网吧多少钱一小时啊?
- 下一篇: P2261 [CQOI2007]余数求和